编写一个规则,列出其元素本身就是列表的列表 在每一行上打印内部元素列表:
示例:
? - printList [[1,a],[2,b]])。
1 a
2 b
解决方案如下:
/* BASE CASE: The list is empty, so there is nothing to print */
printList([]).
printList([P|R]):- printList(P),
!,
nl,
printList(R).
printList([X|R]):- write(X),
!,
printList(R).
当列表为空时,我有printList规则到达基本情况,在这种情况下没有任何内容可以打印。
如果我不在基本情况下(列表不为空),则调用第二个规则 printList([P | R]),现在我有了第一个疑问:
元素P是一个列表,因为Prolog会自动将内部列表作为元素处理?
所以,如果我有类似的东西:
[[1,a],[2,b],[3,c],[4,d]] 我让Prolog以这种方式自动匹配:
P = [1,a] (第一个列表作为头元素)
R = [[2,b],[3,c],[4,d]] (另外3个列表是尾部列表的元素)
然后程序调用head元素(第一个列表)上的 printList 谓词,这个版本的规则会写入当前列表中的所有元素。
这是正确的解释吗?
现在我对这个程序的跟踪有一些疑问,例如,如果我执行这个语句,我得到以下跟踪:
[trace] ?- printList([[1,a], [2,b]]).
Call: (6) printList([[1, a], [2, b]]) ? creep
Call: (7) printList([1, a]) ? creep
Call: (8) printList(1) ? creep
Fail: (8) printList(1) ? creep
Redo: (7) printList([1, a]) ? creep
Call: (8) write(1) ? creep
1
Exit: (8) write(1) ? creep
Call: (8) printList([a]) ? creep
Call: (9) printList(a) ? creep
Fail: (9) printList(a) ? creep
Redo: (8) printList([a]) ? creep
Call: (9) write(a) ? creep
a
Exit: (9) write(a) ? creep
Call: (9) printList([]) ? creep
Exit: (9) printList([]) ? creep
Exit: (8) printList([a]) ? creep
Exit: (7) printList([1, a]) ? creep
Call: (7) nl ? creep
Exit: (7) nl ? creep
Call: (7) printList([[2, b]]) ? creep
Call: (8) printList([2, b]) ? creep
Call: (9) printList(2) ? creep
Fail: (9) printList(2) ? creep
Redo: (8) printList([2, b]) ? creep
Call: (9) write(2) ? creep
2
Exit: (9) write(2) ? creep
Call: (9) printList([b]) ? creep
Call: (10) printList(b) ? creep
Fail: (10) printList(b) ? creep
Redo: (9) printList([b]) ? creep
Call: (10) write(b) ? creep
b
Exit: (10) write(b) ? creep
Call: (10) printList([]) ? creep
Exit: (10) printList([]) ? creep
Exit: (9) printList([b]) ? creep
Exit: (8) printList([2, b]) ? creep
Call: (8) nl ? creep
Exit: (8) nl ? creep
Call: (8) printList([]) ? creep
Exit: (8) printList([]) ? creep
Exit: (7) printList([[2, b]]) ? creep
Exit: (6) printList([[1, a], [2, b]]) ? creep
true.
这对我来说非常清楚(我认为我之前的推理是正确的)但是我不明白为什么每当它到达内部列表中的元素时它会调用 printList 关系(是一个简单的元素而不是列表),例如:
Call: (8) printList(1) ? creep
Fail: (8) printList(1) ? creep
程序考虑了原始列表的第一个列表,然后,为了打印它的第一个元素,为什么在这个简单元素上调用 printList 关系
是因为这个简单的元素又可能是内部列表吗?
类似的东西:
[[[1.1,a1,a2],[1.2,b1,b2]],[2,b]] (其中我有一个包含2个列表和第一个元素的列表它是一个包含2个列表的列表。所以程序检查元素是元素还是内部列表?
答案 0 :(得分:2)
我认为你过分思考它。看一下代码:
printList([P|R]):- printList(P),
在那里你可以看到printList/1
正在与列表的头部统一。 printList/1
匹配列表和仅列表的所有规则都是您,人类可以立即看到的事实。但是Prolog没有“注意到”这个事实,所以如果你打电话,比方说,
printList([1])
第一个匹配规则是上面的规则,因此会立即尝试统一printList(1)
。这自然会失败,因为1不是列表,因此不匹配printList/1
的任何规则。 Prolog然后回溯并尝试下一个规则,就是这样开始的规则:
printList([X|R]):- write(X),
这显然将统一[1]与X = 1,R = [],所以它显然会写第一个元素,一个,然后像往常一样继续。这里没有涉及“内部列表”的魔法,据我所知,它根本不是Prolog中的一个概念(如果在编译器中处理这样的事情,它对Prolog的用户来说是很好的隐藏)。
Prolog不是通灵者;它必须尝试规则以查看它们是否失败,即使该尝试本质上是Horn子句中的失败模式匹配。
我无法将您的第一个问题与第二个问题区分开来,所以我希望这可以解决这两个问题。 :)