Prolog否定更多解决方案

时间:2014-04-17 22:11:27

标签: prolog backtracking negation

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

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找到第一个骗子,它将停止回溯,我找不到任何其他解决方案。也许之后会很明显,但现在我脑子里什么也没有了......

提前致谢(也许对不起我的英语:))

2 个答案:

答案 0 :(得分:5)

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

  • 鹰是鸟吗?
  • 企鹅是鸟吗?
  • 鹰能飞吗?
  • 企鹅可以飞吗?

但你甚至不能问,#34;哪些鸟可以飞?":

?- can_fly(Bird).
false.

如果您希望能够提出更一般的问题,例如,"哪些鸟可以飞?"或者#34;哪些鸟不能飞?",你需要明确列出飞行或非飞行的鸟类。由于大多数鸟类都可以飞行,所以让我们明确列出非飞行鸟类:

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。如果无法证明目标,那就确实如此。它比您正在使用的失效切割组合更清晰。

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

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

答案 1 :(得分:4)

切断失败的东西是一个误导你的反模式。在原文中说这样的话要好得多:

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).

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