7

我有一个确定列表成员资格的标准程序:

member(X, [X|_]).  
member(X, [_|T]) :- member(X, T).

我不明白为什么当我提出以下查询时:

?- member(a,[a,b]).

结果是

True;  
False.

我会认为在使用第一条规则(因为 a 是列表的头部)满足目标时,将返回 True,这将是 if 的结束。似乎它正在尝试使用第二条规则来满足目标并且失败了?

Prolog 解释器是 SWI-Prolog。

4

3 回答 3

7

让我们首先考虑一个类似的查询:[编辑:在添加您自己的定义的情况下执行此操作;member/2已经定义]

?- member(a,[b,a]).
true.

在这种情况下,您会得到最佳答案:只有一种解决方案。但是当交换列表中的元素时,我们得到:

?- member(a,[a,b]).
true ;
false.

从逻辑上讲,两者都只是对查询为真的肯定。

差异的原因是,在第二个查询中,答案是在找到列表元素后true立即给出的。a其余列表[b]不包含拟合元素,但尚未检查。仅根据请求(点击SPACE;)尝试列表的其余部分,结果没有进一步的解决方案。

本质上,当计算完全完成以及仍有一些工作要做时,这个微小的差异会给你一个提示。对于简单的查询,这并没有什么不同,但在更复杂的查询中,这些开放的备选方案(选择点)可能会累积并耗尽内存。

较早的顶层总是询问您是否想查看进一步的解决方案,即使没有。

编辑:

避免询问下一个答案(如果没有)的能力非常依赖于实现细节。即使在同一个系统中,加载同一个程序,你也可能得到不同的结果。但是,在这种情况下,我使用的是 SWI 的内置定义,member/2而您使用的是您自己的定义,它会覆盖内置定义。

SWI 使用以下定义作为内置定义,这在逻辑上与您的定义等价,但使 SWI 更容易避免不必要的选择点——但许多其他系统无法从中受益:

member(B, [C|A]) :-
        member_(A, B, C).

member_(_, A, A).
member_([C|A], B, _) :-
        member_(A, B, C).

使事情变得更加复杂:许多 Prolog 具有不同的顶层,当查询不包含变量时,它从不要求进一步的答案。所以在那些系统(比如 YAP)中,你会得到一个错误的印象。

尝试以下查询来查看:

?- member(X,[1]).
X = 1.

SWI 再次能够确定这是唯一的答案。但是,例如,YAP 不是。

于 2013-01-30T02:00:27.143 回答
2

你用的是“;” 运算符在第一个结果之后然后推返回?我相信这是要求查询寻找更多结果,因为没有结果,所以它是错误的。

于 2013-01-30T01:05:53.613 回答
1

你知道 Prolog 的 cut -!吗?

如果您更改member(X, [X|_]).member(X, [X|_]) :- !.Prolog,将不会在第一个解决方案之后尝试找到另一个解决方案。

于 2013-01-30T02:37:47.220 回答