无法理解重做和绑定

时间:2017-03-25 04:04:16

标签: prolog swi-prolog

我正在学习Prolog,并且无法理解Prolog如何使用这些谓词来访问给定列表中的第n个元素。

elementAt([Element|_], 0, Element).
elementAt([_|Tail], N, Element) :-
    elementAt(Tail, N1, Element),
    N is N1 + 1.

我使用swi-prologs trace命令来了解下面的表达式是如何解决的。

elementAt([0,1,2,3,4,5,6,7], 5, E).

我理解部分迹线但不是所有部分,因此我使用行号复制了迹线以便于参考。我的问题是在跟踪输出之下。

1   Call: (8) elementAt([0, 1, 2, 3, 4, 5, 6, 7], 5, _6554) ? creep
2   Call: (9) elementAt([1, 2, 3, 4, 5, 6, 7], _6836, _6554) ? creep
3   Exit: (9) elementAt([1, 2, 3, 4, 5, 6, 7], 0, 1) ? creep
4   Call: (9) 5 is 0+1 ? creep
5   Fail: (9) 5 is 0+1 ? creep
6   Redo: (9) elementAt([1, 2, 3, 4, 5, 6, 7], _6836, _6554) ? creep
7   Call: (10) elementAt([2, 3, 4, 5, 6, 7], _6836, _6554) ? creep
8   Exit: (10) elementAt([2, 3, 4, 5, 6, 7], 0, 2) ? creep
9   Call: (10) _6840 is 0+1 ? creep
10  Exit: (10) 1 is 0+1 ? creep
11  Exit: (9) elementAt([1, 2, 3, 4, 5, 6, 7], 1, 2) ? creep
12  Call: (9) 5 is 1+1 ? creep
13  Fail: (9) 5 is 1+1 ? creep
14  Redo: (10) elementAt([2, 3, 4, 5, 6, 7], _6836, _6554) ? creep
15  Call: (11) elementAt([3, 4, 5, 6, 7], _6836, _6554) ? creep
16  Exit: (11) elementAt([3, 4, 5, 6, 7], 0, 3) ? creep
17  Call: (11) _6840 is 0+1 ? creep
18  Exit: (11) 1 is 0+1 ? creep
19  Exit: (10) elementAt([2, 3, 4, 5, 6, 7], 1, 3) ? creep
20  Call: (10) _6846 is 1+1 ? creep
21  Exit: (10) 2 is 1+1 ? creep
22  Exit: (9) elementAt([1, 2, 3, 4, 5, 6, 7], 2, 3) ? creep
23  Call: (9) 5 is 2+1 ? creep
24  Fail: (9) 5 is 2+1 ? creep
25  Redo: (11) elementAt([3, 4, 5, 6, 7], _6836, _6554) ? creep
26  Call: (12) elementAt([4, 5, 6, 7], _6836, _6554) ? creep
27  Exit: (12) elementAt([4, 5, 6, 7], 0, 4) ? creep
28  Call: (12) _6840 is 0+1 ? creep
29  Exit: (12) 1 is 0+1 ? creep
30  Exit: (11) elementAt([3, 4, 5, 6, 7], 1, 4) ? creep
31  Call: (11) _6846 is 1+1 ? creep
32  Exit: (11) 2 is 1+1 ? creep
33  Exit: (10) elementAt([2, 3, 4, 5, 6, 7], 2, 4) ? creep
34  Call: (10) _6852 is 2+1 ? creep
35  Exit: (10) 3 is 2+1 ? creep
36  Exit: (9) elementAt([1, 2, 3, 4, 5, 6, 7], 3, 4) ? creep
37  Call: (9) 5 is 3+1 ? creep
38  Fail: (9) 5 is 3+1 ? creep
39  Redo: (12) elementAt([4, 5, 6, 7], _6836, _6554) ? creep
40  Call: (13) elementAt([5, 6, 7], _6836, _6554) ? creep
41  Exit: (13) elementAt([5, 6, 7], 0, 5) ? creep
42  Call: (13) _6840 is 0+1 ? creep
43  Exit: (13) 1 is 0+1 ? creep
44  Exit: (12) elementAt([4, 5, 6, 7], 1, 5) ? creep
45  Call: (12) _6846 is 1+1 ? creep
46  Exit: (12) 2 is 1+1 ? creep
47  Exit: (11) elementAt([3, 4, 5, 6, 7], 2, 5) ? creep
48  Call: (11) _6852 is 2+1 ? creep
49  Exit: (11) 3 is 2+1 ? creep
50  Exit: (10) elementAt([2, 3, 4, 5, 6, 7], 3, 5) ? creep
51  Call: (10) _6858 is 3+1 ? creep
52  Exit: (10) 4 is 3+1 ? creep
53  Exit: (9) elementAt([1, 2, 3, 4, 5, 6, 7], 4, 5) ? creep
54  Call: (9) 5 is 4+1 ? creep
55  Exit: (9) 5 is 4+1 ? creep
56  Exit: (8) elementAt([0, 1, 2, 3, 4, 5, 6, 7], 5, 5) ? creep

第1行到第5行非常清楚。第一个规则匹配将_6836绑定到0. N is N1 + 1约束失败并尝试elementAt([_|Tail], N, Element)谓词。这也意味着_6836不再绑定为0,对吧?

第7行是我不明白的。 Prolog试图重做

elementAt([1, 2, 3, 4, 5, 6, 7], _6836, _6554)

调用会导致第8行的调用

elementAt([2, 3, 4, 5, 6, 7], _6836, _6554)

我注意到第7行应该是_6836的{​​{1}}在第8行也被用作N。为什么Prolog会这样做?

这是两个完全不同的变量。在第14-15行,第25-26行和第39-40行中重复相同的模式。最终它得到了正确的元素,但我真的不明白如何。

我想我不太明白重做是如何运作的,但我没有想法。

1 个答案:

答案 0 :(得分:1)

  

跟踪线6中的N1(_6836)是否与跟踪线7中的N1(_6836)相同?

是的,它是同一个变量。如果您查看trace,您会看到

6  Redo: (9) elementAt([1, 2, 3, 4, 5, 6, 7], _6044, _5790) ? creep 

是源代码行

elementAt(Tail, N1, Element)

所以_6836N1

然后

7  Call: (10) elementAt([2, 3, 4, 5, 6, 7], _6044, _5790) ? creep 

是源代码行

elementAt([_|Tail], N, Element)

请注意,深度已从(9)更改为(10)

所以_6836N

因此N1N是统一的但尚未绑定。我不知道这是否是正确的说法,但我相信如果没有,我会得到纠正。

就我个人而言,我没有多少使用跟踪,我更喜欢在需要时使用这些debugging predicatesgtrace