7

我无法理解为什么我在 prolog 中的代码会根据我放入规则的顺序来执行某些操作。

这是我的数据库:

parent(tom, bob).
parent(tom, liz).
parent(mary, bob).
parent(mary, liz).

male(tom).
male(bob).
female(mary).
female(liz).

以下是规则:

%difference(X, Y) ==> Predicate to check if two people X and Y are not the same person.
difference(X, Y) :- \==(X, Y).
father(X, Y) :- male(X), parent(X, Y), difference(X, Y).
mother(X, Y) :- female(X), parent(X, Y), difference(X, Y).
sibling(X, Y) :-
    difference(X, Y),
    mother(M, X), mother(M, Y),
    father(F, X), father(F, Y).

问题是当我这样做时,

?- sibling(bob, X).

我明白了

X = bob ;
X = liz ;
false.

但是当我改变顺序时(我把差异(X,Y)放在最后一部分)

sibling(X, Y) :-
    mother(M, X), mother(M, Y),
    father(F, X), father(F, Y),
    difference(X, Y).

我打电话给

?- sibling(bob, X).

我明白了

X = liz;
false.

这就是我想要的。

到目前为止,我只看到在进行递归时规则的顺序很重要。所以我不明白鲍勃为什么仍然是他自己的兄弟,只是因为我把差异检查放在了第一位。

谢谢你的帮助!

4

2 回答 2

7

您的问题的实际原因(\==)/2different/2. 它过于频繁地成功了。将其替换为dif/2,您将获得预期的行为。dif/2可用于许多 Prolog 系统,如 SICStus、YAP、B、SWI。您还可以在 ISO-Prolog 中定义一个安全的近似值,如下所示:

iso_dif(X, Y) :-
   X \== Y,
   ( X \= Y -> true
   ; throw(error(instantiation_error,iso_dif/2))
   ).

现在,如果参数没有充分实例化,您将收到实例化错误。Prolog 中止计算并说:我不知道!这比假装它确实有想法而它没有想法要好得多。

使用iso_dif/2你仍然必须将它放在规则的末尾。但这一次,Prolog 会留意它的正确用法。

| ?- iso_dif(a,b).

yes
| ?- iso_dif([a,_],[b,_]).

(8 ms) yes
| ?- iso_dif([a,X],[X,b]).

yes
| ?- iso_dif([a,X],[a,X]).

no
| ?- iso_dif([a,X],[X,X]).
uncaught exception: error(instantiation_error,iso_dif/2)
于 2013-11-27T09:47:21.653 回答
1

这是因为统一的工作方式。如果将差异放在首位,则 X 和 Y 的值尚未统一为任何值。考虑跟踪:

 goal list: [sibling(bob, Z)]
 goal: sibling(bob, Z).
 X-> bob, Y -> Z
 goal list: [difference(bob, Y), mother(M, bob), mother(M, Y), father(F, bob), father(F, Y).]
 goal: difference(bob, Y) --SUCCESS
 goal list: [mother(M, bob), mother(M, Y), father(F, bob), father(F, Y).]
 goal: mother(M, bob)
 ...

当您最后调用差异时,X 和 Y 都已统一,如果它们是相同的值,差异将失败。然后会发生回溯。

使用 prolog 环境的跟踪功能来查看执行过程中逐步发生的情况。

于 2013-11-26T17:09:17.277 回答