我在理解为什么我的prolog代码根据我的规则的顺序做了一些事情时遇到了一些麻烦.
这是我的数据库:
parent(tom, bob).
parent(tom, liz).
parent(mary, bob).
parent(mary, liz).
male(tom).
male(bob).
female(mary).
female(liz).
Run Code Online (Sandbox Code Playgroud)
以下是规则:
%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).
Run Code Online (Sandbox Code Playgroud)
问题是,当我这样做时,
?- sibling(bob, X).
Run Code Online (Sandbox Code Playgroud)
我明白了
X = bob ;
X = liz ;
false.
Run Code Online (Sandbox Code Playgroud)
但是当我改变排序时(我把差异(X,Y)放在最后一部分)
sibling(X, Y) :-
mother(M, X), mother(M, Y),
father(F, X), father(F, Y),
difference(X, Y).
Run Code Online (Sandbox Code Playgroud)
我打电话给
?- sibling(bob, X).
Run Code Online (Sandbox Code Playgroud)
我明白了
X = liz;
false.
Run Code Online (Sandbox Code Playgroud)
这就是我想要的.
到目前为止,我只看到规则的排序在进行递归时很重要.所以我不明白鲍勃是如何仍然是自己的兄弟只是因为我先把差异检查.
谢谢你的帮助!
有关问题的实际原因是(\==)/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))
).
Run Code Online (Sandbox Code Playgroud)
现在,如果参数没有充分实例化,您将获得实例化错误.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)
Run Code Online (Sandbox Code Playgroud)
这是因为统一的运作方式。如果将差异放在首位,则 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)
...
Run Code Online (Sandbox Code Playgroud)
当你把差异调用放在最后时,X和Y都已经统一了,如果它们是相同的值,差异就会失败。那么就会发生回溯。
使用 prolog 环境的跟踪功能来查看执行过程中逐步发生的情况。