为什么以下Prolog程序只返回一个解决方案?

时间:2017-10-22 16:19:52

标签: prolog

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上的类似问题的回答建议使用 SPACE ; 而不是 ENTER ,但我如果我在得到第一个答案后按; SPACE ,请获取false

出了什么问题?

1 个答案:

答案 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] .