Prolog:一个人是自己的兄弟姐妹?

时间:2013-11-26 17:02:02

标签: prolog prolog-dif

我很难理解为什么我的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.

这就是我想要的。

到目前为止,我只看到规则的排序在进行递归时很重要。 所以我不明白鲍勃是如何仍然是自己的兄弟只是因为我先把差异检查。

感谢您的帮助!

2 个答案:

答案 0 :(得分:6)

问题的实际原因是(\==)/2 different/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)

答案 1 :(得分: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环境的跟踪功能查看执行过程中逐步执行的操作。