误解附加清单序言

时间:2012-08-07 19:13:47

标签: prolog

最近我开始学习Prolog,一旦我处理了它,我就有了解它的问题。

我正在研究列表,但我无法理解应该合并两个列表的append/3谓词是如何工作的。

book_append([], L, L). 
book_append([X|L1], L2, [X|L3]) :-
    book_append(L1, L2, L3).

准确地说,我无法理解L2如何附加到主列表中。我试着解释到目前为止我所理解的内容:

只有当第一个列表为空且第二个和第三个列表采用相同的值时,边界条件才会统一。这是对的吗?

第一个问题,也许是愚蠢的,当第一个列表为空时,两个列表必须统一,以便它们采用相同的值。但它们应该是不同的,所以我将失去其中一个价值。

在第二行中,第一个列表的头部附加在第三个列表中并调用相同的函数。

我通常以这种方式使用此功能:book_append([1, 2, 3], [a, b, c], X).

第一行是假的,因为L1不是空的 而第二个应该是:

book_append([1|[2, 3], [a, b, c], [1|L3]) :-
    book_append([2, 3], [a, b, c], L3). 

第一次通话期间L3(我已经知道它是第三个列表的尾部)的价值是多少?它是空的吗?还是一个未实例化的变量?或者它被实例化为L2

4 个答案:

答案 0 :(得分:2)

首先,请this answer@Will Ness(由我)查看this answer。它应该已经回答了你的问题。

然后让我们(快速)解决您的具体问题:

  

第一个问题,也许是愚蠢的,当第一个列表为空时,两个列表必须统一,以便它们采用相同的值。但它们应该是不同的,所以我将失去其中一个价值。

你必须考虑Prolog中值的变化。

基本上价值通过统一而改变。并且只改变一次。这意味着A可以成为[5|B]然后将完成更改,并且将成为您所有程序的更改。 B最终可能会发生变化,A也会以某种方式发生变化,但绑定只会发生一次,如前所述。

所以在这里,你不能“失去”价值,因为你不能重新绑定任何东西。通过将自由变量绑定到正确的内容,统一将尽力匹配List2Result。这样,如果Result是一个自由变量,那么它只会绑定到List2的值。如果两个变量都已绑定,则统一可以做的唯一事情是测试它们是否绑定到相同的值。

关于你的第二个问题,请特别注意我的答案,详细说明绑定以获得更清晰的想法。

答案 1 :(得分:2)

Prolog的逻辑变量(logvars)本质上是命名指针,可以实例化/ “set”(分配值) 只能 。每个logvar都可以处于“尚未设置”状态,或者处于实例化/设置状态。

没有任何绑定可以更改,而没有发生 回溯 (在回溯时,此“指针设置”可以撤消并且logvars可以恢复到以前的未实例化状态,可能稍后再次实例化为其他一些值)。

当“设置”时,它可以指向原子值,如数字(5),符号'a')等。或者它可以指向另一个logvar (意思是,两者变成等价物)。

或者它可以指向一个复合( struct -like,或 named record -like)值,如f(a,B,c),其子实体本身可以是完全实例化(“ground”)值,或者它们可以/包含尚未实例化的logvars本身。

现在,Prolog中的列表'.'(点)的名称(即 functor )下显示为复合词。列表[A|B]实际上是一个复合词'.'(A,B),包含两个子实体,即“arguments”AB

因此,当我们“设置”A = [1|B]时,我们会在计算机内存中的实际真实结构中使A“指向”,标记为名称( functor ){ {1}},有两个字段。第一个字段包含一个数字'.',第二个字段包含一个名为1的logvar,尚未实例化为任何内容。或者用C ++ - 术语来说,它是一个未初始化的指针。

并且 指针正在传递( 引用 )到B的嵌套递归调用中。并且那个指针被设置在那里。这就是book_append“指向”“列表节点”的第二个字段现在指向的内容。

因此,递归调用不需要将任何内容“返回”回Prolog中的“调用者”。它们只是实例化在它们上面设置的部分结构,“充实”这些结构越来越充分。

但是如果我们在列表的顶级节点上有一个句柄,我们就可以访问它的所有子实体,因为它们已经完全实例化了。

所有这些冗长的文本,用C ++术语表示,A在复制列表节点的同时沿着第一个列表进行操作,当它到达第一个列表的末尾时,它设置< em> next 最后复制的列表节点的指针 - 指向调用它的第二个列表的开头。这意味着它是tail recursive modulo cons

答案 2 :(得分:0)

第一行仅适用于第一个列表为空且第二个和第三个列表相同(或者一个是变量等,然后可以采用另一个的值)的情况。所以你不会丢失信息。

为了理解第二行,请记住(使用它的方式),第三个参数是结果(同样,这只是一种可能的用法)。因此,当以这种方式使用时,第二行表示它将返回[X | L3],并且在身体中提到L3(我实际上并不知道正确的术语) - 在哪里?作为新的book_append调用的结果。因此L3将是将第一个列表附加到第二个列表的结果。

答案 3 :(得分:0)

数据库:

book_append([], L, L).
book_append([X|L1], L2, [X|L3]) :- book_append(L1, L2, L3).

致电:

?- book_append([1, 2, 3], [a, b, c], A).

编译器将查看数据库以查找统一信息。 因为第一行不能统一([1,2,3]不能与[])统一,所以第二行将被使用,它将变为: book_append([1 | [2,3],[a,b,c],[1 | L3]): - book_append([2,3],[a,b,c],L3)。 只有来自&#34;的权利条件才会发生统一: - &#34;也有一个统一。 因此,它将再次查看数据库以查找book_append([2,3],[a,b,c],L3)的统一等等。

统一应该如下所示(=是统一的符号):

book_append([1, 2, 3], [a, b, c], A) = 
    book_append([1|[2,3]], [a,b,c], [1|L3]) =
    book_append([2|[3]],   [a,b,c], [2|L3]) =
    book_append([3|[],     [a,b,c], [3|L3]] =
    book_append([],        [a,b,c], [a,b,c])  % book_append([], L, L).
=> A = 1|2|3|[a,b,c]

如果我错了,请纠正我,我刚刚开始为项目学习。