我正在学习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行中重复相同的模式。最终它得到了正确的元素,但我真的不明白如何。
我想我不太明白重做是如何运作的,但我没有想法。
答案 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)
所以_6836
是N1
然后
7 Call: (10) elementAt([2, 3, 4, 5, 6, 7], _6044, _5790) ? creep
是源代码行
elementAt([_|Tail], N, Element)
请注意,深度已从(9)
更改为(10)
所以_6836
是N
因此N1
和N
是统一的但尚未绑定。我不知道这是否是正确的说法,但我相信如果没有,我会得到纠正。
就我个人而言,我没有多少使用跟踪,我更喜欢在需要时使用这些debugging predicates或gtrace
。