SWI-Prolog:检查多个列表中的元素成员资格
SWI-Prolog: Check element membership in multiple lists
所以我有一个成员函数,它告诉我什么时候 X
不在 L
:
not_in(X, L) :- not(member(X,L)).
效果如愿:
83 ?- not_in(5,[3,4]).
true.
不过,我还有一个生成很多列表的函数:
84 ?- manyLists(_,L).
L = [5, 11] ;
L = [3, 4] ;
L = [16, 22] ;
false.
我想做的是检查 X
是否不在任何列表中:
manyLists(_,L), not_in(X,L).
但是,这个 returns:
85 ?- manyLists(_,L), not_in(32,L).
L = [5, 11] ;
L = [3, 4] ;
L = [16, 22] ;
false.
即它应该 return 正确,因为 32 不在任何这些列表中。
我做错了什么?
你没有做错任何事,但你可能没有正确解释你得到的解决方案。
首先,当您有一个成功不止一次的谓词时,这被称为(有点误导)非确定性行为:一个查询 returns 多个 解决方案.
假设你问,"which number is between 1 and 3?":
?- between(1, 3, X).
X = 1 ;
X = 2 ;
X = 3.
你得到三个答案。每个都有一个变量绑定:X = 1
、X = 2
和X = 3
.
?- between(1, 3, X), succ(X, Y).
X = 1, Y = 2 ;
X = 2, Y = 3 ;
X = 3, Y = 4.
现在每个解决方案都有两个变量绑定。
?- between(1, 3, X), X rem 2 =:= 0.
X = 2 ;
false.
如果您无法理解 Prolog 如何尝试为最后一个查询找到证明,您甚至可以查看实际的证明树:
?- trace(between/3), trace('=:='/2).
% between/3: [call,redo,exit,fail]
% (=:=)/2: [call,redo,exit,fail]
true.
[debug] ?- between(1, 3, X), X rem 2 =:= 0.
T Call: (8) between(1, 3, _G1248)
T Exit: (8) between(1, 3, 1)
T Call: (8) 1 rem 2=:=0
T Fail: (8) 1 rem 2=:=0
T Redo: (8) between(1, 3, _G1248)
T Exit: (8) between(1, 3, 2)
T Call: (8) 2 rem 2=:=0
T Exit: (8) 2 rem 2=:=0
X = 2 ;
T Redo: (8) between(1, 3, _G1248)
T Exit: (8) between(1, 3, 3)
T Call: (8) 3 rem 2=:=0
T Fail: (8) 3 rem 2=:=0
false.
关于你的问题:你想证明对于你的列表的所有个可能的绑定,一个数字不在那个列表中。
您的原始查询,已简化:
?- ( L = [5,11] ; L = [3,4] ; L = [16,22] ), \+ member(32, L).
L = [5, 11] ;
L = [3, 4] ;
L = [16, 22].
将其包装在 SWI-Prolog 谓词中 forall/2
:
?- forall( ( L = [5,11] ; L = [3,4] ; L = [16,22] ), \+ member(32, L) ).
true.
?- forall( ( L = [5,11] ; L = [3,4] ; L = [16,22] ), \+ member(3, L) ).
false.
如果你查看forall/2
的帮助,你会看到forall(Cond, Action)
具有语义\+ ( Cond, \+ Action )
,即:"There is no condition for which action cannot be proved."
?- \+ ( ( L = [5,11] ; L = [3,4] ; L = [16,22] ), \+ \+ member(32, L) ).
true.
所以我有一个成员函数,它告诉我什么时候 X
不在 L
:
not_in(X, L) :- not(member(X,L)).
效果如愿:
83 ?- not_in(5,[3,4]).
true.
不过,我还有一个生成很多列表的函数:
84 ?- manyLists(_,L).
L = [5, 11] ;
L = [3, 4] ;
L = [16, 22] ;
false.
我想做的是检查 X
是否不在任何列表中:
manyLists(_,L), not_in(X,L).
但是,这个 returns:
85 ?- manyLists(_,L), not_in(32,L).
L = [5, 11] ;
L = [3, 4] ;
L = [16, 22] ;
false.
即它应该 return 正确,因为 32 不在任何这些列表中。
我做错了什么?
你没有做错任何事,但你可能没有正确解释你得到的解决方案。
首先,当您有一个成功不止一次的谓词时,这被称为(有点误导)非确定性行为:一个查询 returns 多个 解决方案.
假设你问,"which number is between 1 and 3?":
?- between(1, 3, X).
X = 1 ;
X = 2 ;
X = 3.
你得到三个答案。每个都有一个变量绑定:X = 1
、X = 2
和X = 3
.
?- between(1, 3, X), succ(X, Y).
X = 1, Y = 2 ;
X = 2, Y = 3 ;
X = 3, Y = 4.
现在每个解决方案都有两个变量绑定。
?- between(1, 3, X), X rem 2 =:= 0.
X = 2 ;
false.
如果您无法理解 Prolog 如何尝试为最后一个查询找到证明,您甚至可以查看实际的证明树:
?- trace(between/3), trace('=:='/2).
% between/3: [call,redo,exit,fail]
% (=:=)/2: [call,redo,exit,fail]
true.
[debug] ?- between(1, 3, X), X rem 2 =:= 0.
T Call: (8) between(1, 3, _G1248)
T Exit: (8) between(1, 3, 1)
T Call: (8) 1 rem 2=:=0
T Fail: (8) 1 rem 2=:=0
T Redo: (8) between(1, 3, _G1248)
T Exit: (8) between(1, 3, 2)
T Call: (8) 2 rem 2=:=0
T Exit: (8) 2 rem 2=:=0
X = 2 ;
T Redo: (8) between(1, 3, _G1248)
T Exit: (8) between(1, 3, 3)
T Call: (8) 3 rem 2=:=0
T Fail: (8) 3 rem 2=:=0
false.
关于你的问题:你想证明对于你的列表的所有个可能的绑定,一个数字不在那个列表中。
您的原始查询,已简化:
?- ( L = [5,11] ; L = [3,4] ; L = [16,22] ), \+ member(32, L).
L = [5, 11] ;
L = [3, 4] ;
L = [16, 22].
将其包装在 SWI-Prolog 谓词中 forall/2
:
?- forall( ( L = [5,11] ; L = [3,4] ; L = [16,22] ), \+ member(32, L) ).
true.
?- forall( ( L = [5,11] ; L = [3,4] ; L = [16,22] ), \+ member(3, L) ).
false.
如果你查看forall/2
的帮助,你会看到forall(Cond, Action)
具有语义\+ ( Cond, \+ Action )
,即:"There is no condition for which action cannot be proved."
?- \+ ( ( L = [5,11] ; L = [3,4] ; L = [16,22] ), \+ \+ member(32, L) ).
true.