2

如何append/3使用匿名变量,例如以下示例中的变量:

append(_,[b(F,ND,P)|Rest],Visited).

难道我们实际上就不能使用append/2吗?

谢谢您的回答!

4

1 回答 1

2

目标

..., append(_,[b(F,ND,P)|Rest],Visited).

阅读:

在节点列表的某处Visited,有一个b(F, ND, P)带有后续节点的Rest

请注意,可能有不止一个这样的节点,所以很可能在某个地方有一个切口或一个once/1.

实际上我们不能只使用 append/2 吗?

你从哪里挖出那个骨架 - 呃 - 图书馆谓词?但事实上,这可能允许我们实现append/3

myappend(Xs, Ys, Zs) :-
   append([Xs,Ys], Zs).

所以背后的直觉是与 listXs连接的 listYs是 list Zs。从这个声明的角度来看,显然没有区别。还是他们?

至少在程序上是有区别的!为了 ...

?- append([], Ys, Zs), false.
false.

... 终止,但是 ...

?- append([[], Ys], Zs), false.
**LOOPS**

...循环!(在 SWI 和 SICStus 中)让我们看看产生的具体答案(我将使用 SICStus,因为它更紧凑地打印变量,SWI 使用难以阅读的变量,例如_G1376):

| ?- append([], Ys, Zs).
Zs = Ys ? ;
no

| ?- append([[], Ys], Zs).
Ys = [],
Zs = [] ? ;
Ys = [_A],
Zs = [_A] ? ;
Ys = [_A,_B],
Zs = [_A,_B] ? ;
Ys = [_A,_B,_C],
Zs = [_A,_B,_C] ? ; ....

所以append/3产生了一个单一的答案,而append/2似乎产生了无限多的答案。它们如何在声明上是等价的,或者不是?

答案与解决方案

首先,我要指出,Ys = [], Zs = []上面是一个具体的解决方案。接下来是Ys = [_A], Zs = [_A]包含无限多解的答案。这里_A代表无限多的基本术语。所以有一种方法可以将无限多的解决方案折叠(或提升)成一个单一的、优雅的和有限的答案。

现在,append([], Ys, Zs)更进一步,它将所有答案折叠成一个:Ys = Zs. 但是,这是对的吗?这个答案意味着任何术语都可以是Ys. 特别是,比如说,non_list这肯定不是一个列表。想一想:

?- append([a],nonlist,Zs).
Zs = [a|nonlist].

因此,append/3有效的做法是过度概括或将事情提升得太远。其实它的定义是:

append([], Zs, Zs).
append([X|Xs], Ys, [X|Zs]) :-
   append(Xs, Ys, Zs).

事实是:

附有任何东西,实际上是任何东西(包括所有波兰国王)的空列表就是任何东西。

显然,这个事实说明的有点过分了。但正是这种过度概括有助于改善终止属性!而且,如果我们稍加小心,这种过度概括将永远不会出现。(((有点阴暗的交易?))

但是,Prolog 还享有许多其他属性——特别是减轻这个问题的逻辑变量的“单一赋值”属性。同样的技术也经常用于差异列表和 DCG。如果您始终如一地明智地使用它,它将提高性能和终止属性。

于 2015-06-15T11:49:28.223 回答