【问题标题】:Prolog negation with more solutions带有更多解决方案的 Prolog 否定
【发布时间】:2014-04-17 22:11:26
【问题描述】:

我遇到了一个小问题,不知道在哪里可以找到解决方案。你可能听说过飞鸟的问题:

bird(eagle).
bird(penguin).
can_fly(penguin):-!,fail.
can_fly(X):-bird(X).

我试图修改这些知识并将其用于一些“爱情故事”。想象一下这个

maried(a, b).
maried(c, d).
lovers(a, d).
likes(X, Y):-maried(X, Y).

现在我想说“如果 X 与 Y 结婚,但 X 是 Z 的情人,那么 X 不喜欢 Y,但喜欢 Z”。 我试过这个:

likes(X, Y) :- lovers(X, Y).
likes(X, Y) :- maried(X, Y), lovers(X, _),!,fail.
likes(X, Y) :- maried(X, Y).

除非我想评估一个目标,否则它会起作用

likes(A, B).

如果数据库中有更多事实并且Prolog找到第一个作弊者,它将停止回溯,我找不到任何其他解决方案。也许之后会很明显,但现在我什么都不想了..

在此先感谢(也许对我的英语感到抱歉:))

【问题讨论】:

    标签: prolog backtracking negation


    【解决方案1】:

    您的第一个示例已经不太有用了。你可以问:

    • 鹰是鸟吗?
    • 企鹅是鸟吗?
    • 鹰会飞吗?
    • 企鹅会飞吗?

    但你甚至不能问,“哪些鸟会飞?”:

    ?- can_fly(Bird).
    false.
    

    如果您希望能够提出更笼统的问题,例如“哪些鸟会飞?”或“哪些鸟不能飞?”,您需要明确列出会飞的鸟或不会飞的鸟。由于大多数鸟都会飞,让我们明确列出不会飞的鸟:

    bird(eagle).
    bird(penguin).
    bird(ostrich).
    bird(dodo).
    bird(sparrow).
    bird(pigeon).
    
    flightless_bird(penguin).
    flightless_bird(ostrich).
    flightless_bird(dodo).
    
    bird_of_pray(eagle).
    
    extinct(dodo).
    extinct(wooly_mammoth).
    
    can_fly(Bird) :-
        bird(Bird),
        \+ flightless_bird(Bird).
    
    extinct_bird(Bird) :-
        bird(Bird),
        extinct(Bird).
    

    注意使用 ISO 谓词表示否定,\+/1。如果目标不能被证明,这是真的。它比您使用的故障切割组合清洁得多。

    你如何组织你的知识是一个完全不同的问题。我给出的例子是不完整的,不一定是最好的方法。作为一般规则,您应该尝试将您的数据保持在规范化的形式中,事实和事实的子句扮演表格和表格行的角色。

    希望这个答案指向正确的方向。

    【讨论】:

      【解决方案2】:

      cut-fail 是一种误导您的反模式。在原文中这样说会更好:

      bird(eagle).
      bird(penguin).
      
      flightless(penguin).
      
      can_fly(X) :- bird(X), \+ flightless(X).
      

      请参阅@boris 的回答,了解有关此问题的精彩且更详细的讨论。

      所以,你有这个数据库。我将把名字放进去,以便我能更好地理解它。

      married(bill,   hillary).
      married(barack, michelle).
      
      lovers(bill, michelle).
      

      现在你想说的是,已婚人士彼此喜欢,除非他们出轨。好吧,最好在 Prolog 中定义这些术语,这样我们就可以用它们进行推理。创建我们需要用来定义我们的域的语言。看起来像这样:

      cheating(Cheater, SpitedSpouse, Lover) :-
        married(Cheater, SpitedSpouse),
        lovers(Cheater, Lover),
        SpitedSpouse \= Lover.
      

      现在定义likes/2 更容易了!

       likes(Husband, Wife)  :- married(Husband, Wife), \+ cheating(Husband, Wife, _).
       likes(Husband, Lover) :- cheating(Husband, _, Lover).
      

      我们甚至可以正确定义不喜欢:

       dislikes(SpitedSpouse, Lover) :- cheating(_,       SpitedSpouse, Lover).
       dislikes(Cheater, Spouse)     :- cheating(Cheater, Spouse,       _).
      

      看看我们学到了什么:你真正拥有的是两个人之间的婚姻关系,或者是三个人之间的欺骗关系,而你的其他谓词只是这两个基本关系的预测。这很整洁,是吗? :) cheating/3 基本上是经典的“三角恋”。这表明我们可以让程序变得更有效:处理爱情四边形,当然!以此类推。

      注意到一些有趣的事情了吗?这个代码不能“抓住”michelle——她不是和bill一样有罪吗?这强调了一个更大的问题:谓词的性别/方向限制。我认为有这样的具体名词有助于看到逻辑关系,但这是一个应该解决的危险捷径。处理逻辑的一种简单方法是创建这样的谓词:

       spouse(X, Y) :- married(X, Y)
       spouse(X, Y) :- married(Y, X).
      

      当然你必须做更多的检查以确保你没有重复相同的人,但这并不难,然后改变你的变量以减少性别特异性。

      【讨论】:

      • 感谢您的解决方案,但现在我遇到了重复问题。为方便起见,请考虑以下事实:married(bill, hillary).,规则:spouse(X, Y) :- married(X, Y);married(Y, X). 和目标:?- spouse(X, Y).。你有什么线索,如何避免重复?
      • 一个简单的事情就是施加一个约束,比如X @< Y。但是您也可以忽略重复项。任何对称关系都有这个问题;通过设计引入不对称是一个简单的解决方法。另一种选择是定义你的谓词,这样很明显只有一个可以出现在一侧(X is_wife_of YY is_husband_of X)。
      • 对不起,不好的例子..我也在使用规则likes(X, Y) :- spouse(X, Y)。所以X @< Y 不是(也许)我的解决方案。也许这很明显,但我是在命令式范式中长大的,只是不知道如何结合规则来让一切正常工作..
      • 我没有发现问题。也许你应该问一个关于它的新问题?
      猜你喜欢
      • 1970-01-01
      • 2013-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-06
      • 2013-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多