差异列表是否能够“解决”变量在prolog中不可变的事实?
即。如果我使用差异列表实现追加:
diff_append(OpenList, Hole, L2) :-
Hole = L2.
然后运行:
X=[a,b,c|Hole], diff_append(X, Hole, [d,e,f]).
在某种程度上,X已被用作可变变量。为了我们的意图和目的它已被改变?
换句话说,我们已经能够修改X(可变)而不必构建新列表,比如Z(不可变),这使得差异列表具有吸引力。那么为什么不只是有可变变量?
更新
diff_append2(OpenList-Hole,L2):-
Hole=L2.
X=[a,b,c|Ho]-Ho,diff_append2(X,[d,e,f]).
答案 0 :(得分:3)
差异列表用于解决另一个限制:您需要遍历整个列表以追加"追加"到最后(想想一个单链表,你有一个指向第一个元素的指针,但不是指向哨兵)。
在代码中:由于列表[a, b, c]
(传统上)是嵌套术语.(a, .(b, .(c, [])))
,因此在其末尾添加d
意味着"剥离"在使用[]
替换末尾(中心)的.(d, [])
之前的每个字词。因此,要实施append/3
:
append([], L, L).
append([H|T], L, [H|R]) :-
append(T, L, R).
是how it is traditionally implemented。
这是another answer,它涵盖了相当广泛的主题。
那个答案没有进入的东西是图书馆预测"返回"出于效率原因,列表可能会提供谓词的差异列表版本,以防您可能希望附加到列表的末尾。示例包括read_pending_codes/3
和read_pending_chars/3
,或findall/4
的四参数版本。
DCG是处理差异列表的一种便捷方式,无需显式传递列表和尾部的两个参数。
队列的三个最基本的操作:建立一个空队列,向后推,然后从前面弹出:
%% empty_queue(-Queue)
% make an empty queue
empty_queue(queue(0, Q, Q)).
%% queue_head(?Queue, ?Head, ?Queue0)
% Queue, with Head removed, is Queue0
queue_head(queue(s(X), [H|Q], Q0), H, queue(X, Q, Q0)).
%% queue_last(+Queue0, +Last, -Queue)
% Queue0, with Last at its back, is Queue
queue_last(queue(X, Q, [L|Q0]), L, queue(s(X), Q, Q0)).
正如人们应该注意的那样,queue_head/3
会让你从前面的或推送到队列的前面。 queue_last/3
只允许你向后推:一旦你推了一个元素,你就没有(持续时间)访问队列中的元素。
queue/3
术语的第一个参数是为了防止Richard O' Keefe所谓的“幻觉”和#34;变量,即从队列中弹出比推送到它的元素更多的元素。有趣的是,从上面的谓词中省略第一个参数,看看会发生什么:
?- empty_queue(Q0), queue_head(Q0, H, Q1).
Q0 = queue([H|_G341], [H|_G341]),
Q1 = queue(_G341, [H|_G341]).
而不是失败。