Prolog中的差异列表和可变变量

时间:2015-08-10 11:21:19

标签: prolog queue difference-lists

差异列表是否能够“解决”变量在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]).

1 个答案:

答案 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/3read_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]).

而不是失败。