如何append/3
使用匿名变量,例如以下示例中的变量:
append(_,[b(F,ND,P)|Rest],Visited).
难道我们实际上就不能使用append/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。如果您始终如一地明智地使用它,它将提高性能和终止属性。