最近我开始学习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
?
答案 0 :(得分:2)
首先,请this answer和@Will Ness(由我)查看this answer。它应该已经回答了你的问题。
然后让我们(快速)解决您的具体问题:
第一个问题,也许是愚蠢的,当第一个列表为空时,两个列表必须统一,以便它们采用相同的值。但它们应该是不同的,所以我将失去其中一个价值。
你必须考虑Prolog中值的变化。
基本上价值通过统一而改变。并且只改变一次。这意味着A
可以成为[5|B]
然后将完成更改,并且将成为您所有程序的更改。 B
最终可能会发生变化,A
也会以某种方式发生变化,但绑定只会发生一次,如前所述。
所以在这里,你不能“失去”价值,因为你不能重新绑定任何东西。通过将自由变量绑定到正确的内容,统一将尽力匹配List2
和Result
。这样,如果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”,A
和B
。
因此,当我们“设置”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]
如果我错了,请纠正我,我刚刚开始为项目学习。