谓词 'append/3' 如何与 Prolog 中的匿名变量一起使用?
How does the predicate 'append/3' work with an anonymous variable in Prolog?
append/3
究竟如何使用匿名变量,如下例所示:
append(_,[b(F,ND,P)|Rest],Visited).
事实上我们不能只使用 append/2
吗?
谢谢您的回答!
目标
..., append(_,[b(F,ND,P)|Rest],Visited).
阅读:
Somewhere in the list of Visited
nodes, there is a b(F, ND, P)
with subsequent nodes Rest
.
请注意,可能有不止一个这样的节点,所以很可能在某个地方有一个切口或 once/1
。
Couldn't we in fact just use append/2?
你是从哪里挖出那个骨架——呃——图书馆谓词的?但实际上,这可能允许我们实现 append/3
:
myappend(Xs, Ys, Zs) :-
append([Xs,Ys], Zs).
所以背后的直觉是列表 Xs
与列表 Ys
连接在一起就是列表 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).
事实是:
The empty list appended with anything, really anything (including all Polish kings), is just that anything.
显然这个事实有点过分了。但正是这种过度概括有助于改善终止属性!而且,如果我们小心一点,这种过度概括永远不会表现出来。 ((有点阴暗的交易?))
但是,Prolog 享有许多其他属性 - 特别是减轻此问题的逻辑变量的 "single assignment" 属性。同样的技术也经常用于差异列表和 DCG。如果您始终如一且明智地使用它,它将提高性能和终止属性。
append/3
究竟如何使用匿名变量,如下例所示:
append(_,[b(F,ND,P)|Rest],Visited).
事实上我们不能只使用 append/2
吗?
谢谢您的回答!
目标
..., append(_,[b(F,ND,P)|Rest],Visited).
阅读:
Somewhere in the list of
Visited
nodes, there is ab(F, ND, P)
with subsequent nodesRest
.
请注意,可能有不止一个这样的节点,所以很可能在某个地方有一个切口或 once/1
。
Couldn't we in fact just use append/2?
你是从哪里挖出那个骨架——呃——图书馆谓词的?但实际上,这可能允许我们实现 append/3
:
myappend(Xs, Ys, Zs) :-
append([Xs,Ys], Zs).
所以背后的直觉是列表 Xs
与列表 Ys
连接在一起就是列表 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).
事实是:
The empty list appended with anything, really anything (including all Polish kings), is just that anything.
显然这个事实有点过分了。但正是这种过度概括有助于改善终止属性!而且,如果我们小心一点,这种过度概括永远不会表现出来。 ((有点阴暗的交易?))
但是,Prolog 享有许多其他属性 - 特别是减轻此问题的逻辑变量的 "single assignment" 属性。同样的技术也经常用于差异列表和 DCG。如果您始终如一且明智地使用它,它将提高性能和终止属性。