contains(X, L) :- [X|_] = L.
contains(X, L) :- [Y|Z] = L, Y \= X, contains(X, Z).
f(R, L1, Res) :-
(R,T) = X,
contains(X, L1),
Res = T.
?- f(1, [(1,2), (1,3)], R).
只给出一个R值,即2,但我希望它返回R 2和3的2个值。
对stackoverflow.com上的类似prolog问题的回答建议使用 SPACE 或; 而不是 ENTER ,但我如果我在得到第一个答案后按; 或 SPACE ,请获取false
。
出了什么问题?
答案 0 :(得分:2)
您的contains/2
定义为:
contains(X, L) :-
[X|_] = L.
contains(X, L) :-
[Y|Z] = L,
Y \= X,
contains(X, Z).
您的Y \= X
(此处以粗体显示)会阻止尾部 contains/2
上的Z
递归一旦找到与列表头部统一的X
。实际上,如果Y = X
,则Y \= X
为假(因为Y \= X
是\+ X = Y
的缩写)。如果Y \= X
失败,我们就无法调用contains(X, Z)
,因此无法检查列表中的其他成员是否可以发出。
所以我们可以删除该语句并写下:
contains(X, L) :-
[X|_] = L.
contains(X, L) :-
[Y|Z] = L,
contains(X, Z).
现在contains/2
的工作方式与member/2
相同。
然而,代码并不是非常优雅:你可以在头部完成身体的统一。此外,我们现在有一个未在第一个子句中使用的变量L
,以及第二个子句中未使用的变量Y
。我们可以将其重写为:
contains(X, [X|_]).
contains(X, [_|T]) :-
contains(X, T).
就是这样。现在你的f/3
会起作用,虽然它不是很优雅。我们也可以将其重写为:
f(R, L, T) :-
contains((R,T), L).
现在我们的f/3
谓词在不同的方向上工作:
?- f(1, [(1,2), (1,3)], R).
R = 2 ;
R = 3 ;
false.
?- f(X, [(1,2), (1,3)], 2).
X = 1 ;
false.
?- f(X, [(1,2), (1,3)], 3).
X = 1 ;
false.
?- f(X, L, 3).
L = [ (X, 3)|_G1262] ;
L = [_G1261, (X, 3)|_G1265] ;
L = [_G1261, _G1264, (X, 3)|_G1268] ;
L = [_G1261, _G1264, _G1267, (X, 3)|_G1271] .
?- f(1, L, 3).
L = [ (1, 3)|_G1250] ;
L = [_G1249, (1, 3)|_G1253] ;
L = [_G1249, _G1252, (1, 3)|_G1256] .