Prolog 为什么会员/2没有立即返回
我需要一个谓词来判断元素是否在列表中。我试图使用member/2,但我注意到一个奇怪的行为 当我调用类似于Prolog 为什么会员/2没有立即返回,prolog,Prolog,我需要一个谓词来判断元素是否在列表中。我试图使用member/2,但我注意到一个奇怪的行为 当我调用类似于member(1[1,2,3])的东西时,SWI prolog输出true,并等待我按enter键,然后执行终止。当元素不在列表中时,不会发生这种情况 我有两个问题: 为什么会这样 立即返回的member/2的代码是什么 为什么会这样 member/2的定义允许多次成功,即使找到了完全相同的解决方案。在您的列表中,所有元素都不同。但是考虑到最后两个额外的1的情况: ?- member(1,[
member(1[1,2,3])的东西时,
SWI prolog输出true
,并等待我按enter键,然后执行终止。当元素不在列表中时,不会发生这种情况
我有两个问题:
member/2
的定义允许多次成功,即使找到了完全相同的解决方案。在您的列表中,所有元素都不同。但是考虑到最后两个额外的1的情况:
?- member(1,[1,2,3,1,1]).
true ;
true ;
true.
memberd/2
?- memberd(1,[1,2,3,1,1]).
true.
?- memberd(X,[1,2,3,1,1]).
X = 1 ;
X = 2 ;
X = 3 ;
false.
区别很容易理解<代码>成员/2基本上定义为:
member(X, [X|_Xs]).
member(E, [_X|Xs]) :-
member(E, Xs).
请注意,这两个条款并不相互排斥!这就是为什么即使已经找到解决方案,它也会搜索替代解决方案的原因。在规则中,E
和\ux
可能是相同的
通过确保E
和X
在规则中不同,我们得到了memberd/2
的第一个定义:
memberd(X, [X|_Xs]).
memberd(E, [X|Xs]) :-
dif(E, X),
memberd(E, Xs).
由于此dif/2
规则仅在当前元素与E
不同时才被考虑。然而,这里缺少的是Prolog在得出它们不相交之前仍然需要考虑两者。
完整的定义包含一些技术细节,以避免无用的选择
memberd(X, [E|Es]) :-
if_(X = E, true, memberd(X, Es)).
使用库(reif)
对于
和
这扩展到:
memberd(X, [E|Es]) :-
( X\=E
-> memberd(X, Es)
; X==E
-> true
; X=E,
true
; dif(X, E),
memberd(X, Es)
).
这是第二个问题的另一个答案
X
是否是Es
的成员,并且两者都是地线,则可以使用
memberchk(X, Es).
memberchk/2
是一个,但如果不是,则可以将其定义为
memberchk(X, Es) :-
member(X, Es),
!.
成员/2
调用后的剪切(!
)会告诉Prolog忘记调用可能仍然需要尝试的任何其他选择
您的示例决定性地(立即)成功:
但是请注意,memberchk/2
与member/2
有很大不同。例如:
?- findall(X, member(X, [1, 2, 3]), Xs).
Xs = [1, 2, 3].
?- findall(X, memberchk(X, [1, 2, 3]), Xs).
Xs = [1].
没错,我要的是荣誉。
?- findall(X, member(X, [1, 2, 3]), Xs).
Xs = [1, 2, 3].
?- findall(X, memberchk(X, [1, 2, 3]), Xs).
Xs = [1].