3

线索

四位客人(Mustard 上校、Plum 教授、Scarlett 小姐、Green 女士)参加了在 Boddy 先生家中的晚宴。突然,灯灭了!当他们回来时,博迪先生死在桌子中间。每个人都是嫌疑人。经过进一步检查,以下事实浮出水面:

  • 博迪先生与格林女士有染。
  • 普拉姆教授与格林女士结婚。
  • 博迪先生非常富有。
  • 芥末上校非常贪婪。
  • 斯嘉丽小姐也和博迪先生有染。

谋杀有两种可能的动机:

  • 仇恨:如果另一个人与他/她的配偶有染,那么这个人就会讨厌另一个人。
  • 贪婪:如果有人贪婪而不富有,而受害者是富有的,他们愿意杀人。

A 部分:在你的 Prolog 程序中写下上述事实和规则。使用以下人员名称:colMustard、profPlum、missScarlet、msGreen、mrBoddy。小心你如何编码(或不编码)对称关系,比如婚姻——你不想要无限循环!married(X,Y) :- married(Y,X) % INFINITE LOOP

?-suspect(Killer,mrBoddy)
Killer = suspect_name_1
Killer = suspect_name_2
etc.

B 部分:写一个谓词,suspect/2,确定嫌疑人可能是谁,即谁有动机。

?-suspect(Killer,mrBoddy)
Killer = unique_suspect.

C 部分:将一个事实添加到您的数据库中,这将导致存在一个独特的嫌疑人。在您的源注释中清楚地指出这一行,以便可以将其删除/添加以进行评分。

?-suspect(Killer,mrBoddy)
Killer = unique_suspect.

每当我输入

suspect(Killer,mrBoddy).

我明白了

suspect(Killer,mrBoddy).
Killer = profPlum

我迷路了

Killer = colMustard.

这是我的来源。

%8) Clue

%facts

affair(mrBoddy,msGreen).
affair(missScarlett, mrBoddy).
affair(X,Y) :- affair(X,Y), affair(Y,X).

married(profPlum, msGreen).
married(X,Y) :- married(X,Y), married(Y,X).

rich(mrBoddy).
greedy(colMustard).

%rules

hate(X,Y) :- married(X,Spouse), affair(Y,Spouse).
greed(X,Y) :- greedy(X), not(rich(X)), rich(Y).


%suspect

suspect(X,Y):- hate(X,Y).
suspect(X,Y):- greed(X,Y).
4

2 回答 2

3

你的程序有两种问题。一是在程序层面:您观察到 Prolog 循环;另一个是在逻辑层——Prolog 的人称之为声明层。由于第一个烦人的事情是这个无限循环,让我们首先缩小范围。实际上我们得到:

?- suspect(Killer,mrBoddy).
Killer = profPlum ;
ERROR: Out of local stack

您现在有多种选择来缩小此问题的范围。要么,选择另一个答案并调用示踪剂。虽然跟踪器可能会向您显示真正的罪魁祸首,但它很可能会在其中穿插许多不相关的步骤。太多了,你的思想会溢出。

另一种选择是通过将目标添加false到程序中来手动修改程序。false我会在仍然循环的同时添加尽可能多的目标。最大的优势是,通过这种方式,您将在源代码中看到真正的罪魁祸首(或者更准确地说,可能是许多此类罪魁祸首之一)。1尝试了一下后,这就是我得到的

?- 嫌疑人(杀手,先生博迪),的。

已婚(profPlum,msGreen):-。
已婚(X,Y):-已婚(X,Y),已婚(Y,X)。

讨厌(X,Y):-已婚(X,配偶),外遇(Y,配偶)。

嫌疑人(X,Y):-讨厌(X,Y),嫌疑人(X,Y):-,贪婪(X,Y)

您程序的所有剩余部分都无关紧要,也就是说,它们不再被使用。所以本质上是规则

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

是罪魁祸首。

现在,对于它的声明部分。这条规则到底意味着什么?为了理解它,我将其解释:-为一种暗示。因此,只要写在右侧的内容是正确的,我们就可以得出写在左侧的结论。在这种情况下:

前提X是已婚YY已婚,X
我们可以得出结论,
X已婚Y

这个结论总结了我们无论如何都认为是真的。因此,从逻辑上讲,它没有定义任何新的东西。您可以删除规则以获得相同的结果 - 以声明方式。所以married(profPlum, msGreen)成立但married(msGreen, profPlum)不成立。换句话说,正如您所声称的,您的规则不正确。

要解决此问题,请删除规则,将所有事实重命名为husband_wife/2并添加定义

married(M,F) :- husband_wife(M,F).
married(F,M) :- husband_wife(M,F).

所以这里实际更深层次的问题是一个逻辑错误。此外,Prolog 的证明机制非常简单,将其变成一个循环。但这只不过是原始逻辑问题的一个受欢迎的借口。2


脚注
1 此方法仅适用于纯单调片段。非单调结构与片段类似not/1(\+)/1不得出现在片段中。
2 @larsmans 对此示例很感兴趣。

于 2014-06-11T15:31:50.813 回答
1

问题是谓词的递归规则affair/2 and married/2。尝试使用它们很容易导致无限循环(即直到堆栈内存耗尽)。您必须在每种情况下使用不同的谓词来表示如果 X 与 Y 有染,则 Y 与 X 有染。您还需要更改suspect/2谓词的定义以调用这些新谓词。

为了更好地理解为什么会出现无限循环,请使用 Prolog 系统的跟踪工具。尝试:

?- trace, suspect(Killer, mrBoddy).

一步一步走。

于 2013-11-19T00:51:19.530 回答