【问题标题】:Prolog: a person is a sibling of himself?Prolog:一个人是他自己的兄弟姐妹?
【发布时间】:2013-11-26 17:02:02
【问题描述】:

我无法理解为什么我在 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.

这就是我想要的。

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

感谢您的帮助!

【问题讨论】:

    标签: prolog prolog-dif


    【解决方案1】:

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

    【讨论】:

    • 它不是你所说的“单调”。例如,我有“?- iso_dif(X,4), X=3”。给出错误。但是“?- X=3,iso_dif(X, 4)”。成功。来自此处的示例:stackoverflow.com/a/36109228/502187
    • @j4nbur53:请重新阅读我的回答。它非常清楚地涵盖了错误的情况。
    • W.r.t.:“如果你把它放在“规则的末尾”,你很可能最终会出现在“数据日志”中,并且可以直接使用 (\==)/2”。这是一个误解:当你单独使用 (\==)/2 时,不能保证结果是正确的。但是对于iso_dif/2,只要没有错误,它们就是正确的。
    • 谓词 ground/1 可能比谓词 (\=)/2 更快,并且它不会唤醒协同程序。业务案例到底是什么?您是否有工作示例,其中 iso_dif/2 优于 ground/1 保护 (\==)/2 或 dif/2。
    • @j4nbur53:列表的任何比较!如果我想测试一个列表是否为“非空”之类的
    【解决方案2】:

    这是因为统一的工作方式。如果将差异放在首位,则 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 环境的跟踪功能来查看在执行过程中逐步发生的情况。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-12
      • 1970-01-01
      • 2019-05-06
      • 2012-07-23
      • 1970-01-01
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      相关资源
      最近更新 更多