给出以下知识库:
car(X) :- ferrari(X).
car(X) :- bmw(X).
car(X) :- ford(X).
ferrari(f).
ferrari(y).
bmw(b).
ford(a).
为什么当我查询它们时,这两个(看似相同)规则产生完全不同的结果?
-- Rule one (returns all the cards except ford
loves(lana,X) :- \+ ford(X), car(X).
-- Rule two (returns nothing, just fails)
loves(lana,X) :- car(X), \+ ford(X).
答案 0 :(得分:2)
我认为您的示例向后,例如:
?- car(X), \+ ford(X).
X = f ;
X = y ;
X = b ;
false.
?- \+ ford(X), car(X).
false.
这里的问题很简单,即否定失败意味着否定永远无法建立约束。 Prolog否定的工作方式,它试图证明查询,然后结果(成功或失败)被倒置。因为成功转化为失败,所以没有建立绑定。
在第一个查询中,Prolog首先搜索汽车(X)。一旦具有绑定,它就会尝试证明X是福特。如果X是福特,则查询失败;否则,查询失败。否则,查询成功。因此Prolog发现f,并且f是汽车,并且ford(f)失败,因此查询成功。您要求它提供更多解决方案,并最终找到car(a)并询问ford(a),该方法成功,因此查询失败,并且X = a永远不会将其返回给用户。
在第二种情况下,Prolog首先尝试找到福特(X)。这成功地建立了X = a,因此求反将其反过来,我们失败了。 Prolog没有其他地方可以备份,因此查询只会失败。没有其他尝试。正如@WillNess所指出的,要么是福特(X),要么就是没有。
换句话说,在第一个查询中,您正在生成所有汽车,然后询问特定汽车是否是福特汽车。在第二个查询中,您将生成所有 fords ,然后使查询失败为ford(X)
将永远不会生成非福德。
答案 1 :(得分:1)
我一直牢记的一个口号是:“ Prolog的'not'意味着,'不能证明'”。它会有所帮助。
在查询\+ford(X), car(X)
中,第一个目标\+ford(X)
试图证明ford(X)
,证明它并因此失败。
当一个目标失败时,在它之前的一个目标(即\+ford(X)
之前)会发生回溯,但是在查询中\+ford(X)
之前没有任何目标。无需重试,失败是最终的。
实际上,就好像它被定义为\+(X) :- X, !, fail
。
我认为,另一种阅读方式是\+ford(X)
和免费的X
表示“不存在任何X
使得ford(X)
成立“ 。显然,这不是事实。这样的X
确实存在:它是X=a
。