我有一个确定列表成员资格的标准程序:
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
我不明白为什么当我提出以下查询时:
?- member(a,[a,b]).
结果是
True;
False.
我会认为在使用第一条规则(因为 a 是列表的头部)满足目标时,将返回 True,这将是 if 的结束。似乎它正在尝试使用第二条规则来满足目标并且失败了?
Prolog 解释器是 SWI-Prolog。
我有一个确定列表成员资格的标准程序:
member(X, [X|_]).
member(X, [_|T]) :- member(X, T).
我不明白为什么当我提出以下查询时:
?- member(a,[a,b]).
结果是
True;
False.
我会认为在使用第一条规则(因为 a 是列表的头部)满足目标时,将返回 True,这将是 if 的结束。似乎它正在尝试使用第二条规则来满足目标并且失败了?
Prolog 解释器是 SWI-Prolog。
让我们首先考虑一个类似的查询:[编辑:在不添加您自己的定义的情况下执行此操作;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 不是。
你用的是“;” 运算符在第一个结果之后然后推返回?我相信这是要求查询寻找更多结果,因为没有结果,所以它是错误的。
你知道 Prolog 的 cut -!
吗?
如果您更改member(X, [X|_]).
为member(X, [X|_]) :- !.
Prolog,将不会在第一个解决方案之后尝试找到另一个解决方案。