问题描述
我在 this answer 中找到了这个 Prolog 代码,它使用差异列表实现了一个队列:
MANIFEST.in
做这样的事情它按预期工作:
%% 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,Q0)).
%% queue_last(+Queue0,+Last,-Queue)
% Queue0,with Last at its back,is Queue
queue_last(queue(X,[L|Q0]),L,queue(s(X),Q0)).
我明白了
...,empty_queue(Q),queue_last(Q,999,Q_),writeln(Q_),....
如果我用这个片段观察 queue(s(0),[999|_3076],_3076)
的值,也很有趣:
Q
我明白了:
empty_queue(Q),writeln(Q),writeln(Q)
我想应该是这样的,因为差异导致空列表,所以它们有点等价。
问题是,在命令之后
queue(0,_3750,_3750)
queue(0,[999|_3758],[999|_3758])
我不能重复使用 queue_last(Q,Q_)
来创建 Q
,例如:
Q__
因为 empty_queue(Q),888,Q__)
的绑定失败。
queue_last(queue(X,Q0)).
我该如何解决这个问题?有一些解决方法吗? (总是使用差异列表)
解决方法
我无法重复使用 Q
来创建 Q__
那是因为您必须使用称为 Q_
的“线程化”新结构。旧的 Q
是一个燃烧器,必须丢弃。它不再正确描述“差异列表”。
?- empty_queue(Q1),queue_last(Q1,999,Q2),queue_last(Q2,888,Q3).
Q1 = queue(0,[999,888|_14714],888|_14714]),% Useless
Q2 = queue(s(0),[888|_14714]),% Burnt
Q3 = queue(s(s(0)),_14714). % Correct,valid
在 empty_queue(Q1)
调用之后,这是 Q1
:
queue
├── arg 0: 0
├── arg 1: ----+---> <empty cell #1>
| |
└── arg 2: ----+
在 queue_last(Q1,Q2)
调用之后,这是 Q1
和 Q2
:
Q1
(无效)
queue
├── arg 0: 0
├── arg 1: ----+---->[|]
| | / \
| | 999 <empty cell #2>
| |
└── arg 2: ----+
Q2
(有效)
queue
├── arg 0: s(0)
├── arg 1: --------->[|]
| / \
| 999 <empty cell #2>
| ^
| |
└── arg 2: ----------------+
在 queue_last(Q2,Q3)
调用之后,这是 Q1
、Q2
和 Q3
:
Q1
(无效)
queue
├── arg 0: 0
├── arg 1: ----+---->[|]
| | / \
| | 999 [|]
| | / \
└── arg 2: ----+ 888 <empty cell #3>
Q2
(无效)
queue
├── arg 0: s(0)
├── arg 1: --------->[|]
| / \
| 999 [|]<------------------+
| / \ |
| 888 <empty cell #3> |
| |
└── arg 2: ----------------------------------+
Q3
(有效)
queue
├── arg 0: s(s(0))
├── arg 1: --------->[|]
| / \
| 999 [|]
| / \
| 888 <empty cell #3>
| ^
| |
└── arg 2: ----------------------+
,
Prolog 变量不能重新分配。你不能重复使用它们。我不知道调用变量“燃烧”是否有很大帮助,它们没有被燃烧,它们绑定到一个具体的值。
不要使用“write”和朋友,除非你正在做一些复杂的打印风格的调试。在顶层尝试一下,无论如何您都会打印出所有内容。以下是如何使用此队列实现。请注意,我使用了 Q0
、Q1
、Q2
等,因为一旦有多个下划线,我就无法计算下划线。
Enqueueing a
,然后是队列末尾的 b
:
?- empty_queue(Q0),queue_last(Q0,a,Q1),b,Q2).
Q0 = queue(0,[a,b|_15096],b|_15096]),Q1 = queue(s(0),[b|_15096]),Q2 = queue(s(s(0)),_15096).
入队 a
,然后是 b
,然后弹出你入队的第一个值(FIFO 顺序):
?- empty_queue(Q0),queue_head(Q2,Popped,Q3).
Q0 = queue(0,b|_17772],b|_17772]),[b|_17772]),_17772),Popped = a,Q3 = queue(s(0),[b|_17772],_17772).
在前面推两次,然后弹出(LIFO 顺序):
?- empty_queue(Q0),queue_head(Q1,x,Q0),y,_21688,_21688),Q1 = Q3,[x|_21688],[y,x|_21688],Popped = y.
我在您的问题下方的评论中链接的答案(这里又是:https://stackoverflow.com/a/31925828/14411997)详细解释了这是如何工作的。它还包含指向其他相关问答等的链接。