1

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

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

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

4

2 回答 2

5

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

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

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

?- 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. 如果目标不能被证明,这是真的。它比您使用的故障切割组合清洁得多。

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

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

于 2014-04-18T06:02:37.780 回答
4

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

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

于 2014-04-18T06:02:02.790 回答