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].