📜  Prolog 中的列表

📅  最后修改于: 2022-05-13 01:55:27.129000             🧑  作者: Mango

Prolog 中的列表

列表是项目的集合,不一定是同质的。在 Prolog 中,列表是内置的数据结构。列表可用于表示集合、堆栈、队列、链表以及树、图等几种复杂的数据结构。

列表的基本符号和属性:

  • Prolog 中的列表是项目的有序集合,表示为 [i1, i2, ..., in]。
  • 与其他编程语言中的数组不同,我们可以直接访问数组的任何元素,prolog 列表只允许直接访问第一个元素,它表示为 Head。因此,我们可以将序言列表写为: [Head | Rest],其中 Rest 是列表的其余部分,不包括第一个元素 Head。
  • Prolog 列表允许列表项的非同质数据类型。
  • prolog 中也允许嵌套任意深度的列表。

一些示例列表如下所示:

[]            % empty list
[a]            % singleton list
[hello, world]        % 2 element list
[[1,2,3,4], p, this] % 3 element list 
[[[1, 2], [3, 4]], [[a, b], [x, y]]].    
% nested list (3 level nesting)    

管道 (|)运算符:

在 prolog 中,列表只有一个运算符,称为管道,用 | 表示。此运算符用于在列表的开头附加一个元素。管道运算符的语法如下:

[a | L]
Here L is a list and a is a single element.

例如:

If, L = [b,c,d]
Then, [a | L] will result in [a,b,c,d]

剪切(!)运算符:

在 Prolog 中,Cut运算符,用 ! 表示是一个永远成功但不能回头的目标。例如,考虑以下程序来查找 2 个数字之间的最大元素:

max_element(X, Y, X) :- X > Y.    % If X > Y, then X is the max element
max_element(X, Y, Y) :- X =< Y.    % If X <= Y, then Y is the max element

在这里,如果我们将目标设置为:

?- max_element(5, 2, Ans).

这个目标与第一条规则相匹配,因为 5 > 2 并且程序返回 Ans = 5。但程序并没有就此停止。它还会继续检查下一条规则。但是由于这两个规则是互补的,我们可以使用 cut 来修改这个程序,如下所示:

% If X > Y, max element is X and do not 
check the next rule for the current goal
max_element(X, Y, X) :- X > Y, !. 

% If the first rule fails, then Y will
definitely be the max element.

% Therefore, no need to put conditionals anymore
max_element(X, Y, Y).    

Prolog 列表上的操作:

1. 求列表 L 的长度

% length of empty list is 0 (base case)
list_length([], 0).
list_length([_ | L], N) :-
    list_length(L, N1),
    N is N1 + 1.     
    % If length of L is N1, then length of [_ | L] will be N1 + 1

询问:

?- list_length([a, b, c, d], N).
N = 4.

2.判断一个元素X是否属于一个列表L

is_member(X, [X | _]) :- !.    % If the head of the list is X
 
 is_member(X, [_ | Rest]) :-    % else recur for the rest of the list
     is_member(X, Rest).

询问:

?- is_member(c, [a, b, c, d]).
true.
?- is_member(f, [a, b, c, d]).
false.

3. 在另一个列表 L1 的末尾附加一个列表 L2,并将结果列表放入 L3

% If L1 is empty, resultant list will be equal to L2 (base case)
append_list([], L2, L2).    

append_list([X | L1], L2, [X | L3]) :-
    append_list(L1, L2, L3).

询问:

?- append_list([a, b, c], [p, q], Ans).

Ans = [a, b, c, p, q].

4. 在列表 L 的末尾插入一个元素 X

insert_end(L, X, NewL) :-
append_list(L, [X], NewL).

询问:

?- insert_end([1, 2, 3], 7, Ans).
Ans = [1, 2, 3, 7].

5. 从列表 L 中删除第一次出现的元素 X

% Deletion of any element from empty list will produce empty list(base case)
delete_element(_, [], []).    

delete_element(X, [X | L], L) :- !.

delete_element(X, [Y | L], [Y | L1]) :-
    delete_element(X, L, L1).

询问:

?- delete_element(b, [a, b, c, b, d], Ans).
Ans = [a, c, b, d].