关于在Prolog中打印列表列表的程序的声明含义的一些疑问

时间:2013-04-22 10:42:08

标签: prolog

  

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

     

示例:

     

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

1 个答案:

答案 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子句中的失败模式匹配。

我无法将您的第一个问题与第二个问题区分开来,所以我希望这可以解决这两个问题。 :)