-1

编写一个规则,获取一个列表,其元素本身就是列表,并在每一行打印内部列表的元素:

例子:

?- printList[[1,a],[2,b]])。

1个

2 乙

解决方案如下:

/* 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个列表是尾列表的元素)

然后程序调用printList然后程序在头元素(第一个列表)上

这个解释对吗?

现在我对这个程序的trace有一些疑问,例如如果我执行这个语句,我会得到以下trace:

[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 个列表的列表。所以程序检查元素是元素还是内部列表?

4

1 回答 1

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 = [] 统一起来,因此它显然会编写第一个元素,即 one,然后照常进行。这里没有涉及“内部列表”的魔法,据我所知,这在 Prolog 中根本不是一个概念(如果在编译器中处理这样的事情,它对 Prolog 的用户来说是隐藏的)。

Prolog 不是通灵的。它必须尝试规则以查看它们是否失败,即使该尝试本质上是 Horn 子句头部中的模式匹配失败。

我无法区分您的第一个问题和第二个问题,所以我希望这两个问题都能回答。:)

于 2013-04-22T14:08:27.693 回答