10

以下故事来自 N. Wirth (1976) 的算法 + 数据结构 = 程序。

我嫁给了一个寡妇(我们称她为 W),她有一个成年女儿(称她为 D)。我的父亲(F)经常来看我们,他爱上了我的继女并娶了她。于是,父亲成了我的女婿,继女成了我的母亲。几个月后,我妻子生了一个儿子(S1),他成为我父亲和叔叔的姐夫。我父亲的这个妻子,也就是我的继女,也有一个儿子(S2)。

我正在尝试在 prolog 中对这些关系进行建模,因此最终我可以输入:

| ?- grandfather(i,i).

对于我是否是我自己的爷爷,我会得到“是”或“否”。

这是我到目前为止编写的代码(grandpa.pl):

aunt(X,Y):-
    sibling(X,Z),
    parent(Z,Y),
    female(X).

brother(X,Y):-
    sibling(X,Y),
    male(X).

brother_in_law(X,Y):-
    child(X,Z),
    married(Z,W),
    parent(W,Y),
    not(sibling(X,Y)),
    male(X).

brother_in_law(s1,f).

child(X,Y):-
    parent(Y,X).

daughter(X,Y):-
    parent(Y,X),
    child(X,Y),
    female(X).

daughter(d,w).

father(X,Y):-
    parent(X,Y),
    male(X).

father(f,i).

father_in_law(X,Y):-
    child(X,Z),
    married(Y,Z),
    not(child(X,Y)),
    male(X).

grandparent(X,Y):-
    parent(X,Z),
    parent(Z,Y).

grandmother(X,Y):-
    grandparent(X,Y),
    female(X).

grandfather(X,Y):-
    grandparent(X,Y),
    male(X).

grandchild(X,Y):-
    child(X,Z),
    child(Z,Y).

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

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

married(i,w).
married(f,d).

mother(X,Y):-
    parent(X,Y),
    female(X).

parent(X,Y):-
    child(Y,X).

sibling(X,Y):-
    parent(Z,X),
    parent(Z,Y).

sister(X,Y):-
    sibling(X,Y),
    female(X).

son(X,Y):-
    parent(Y,X),
    male(X).

son(s1,w).
son(s2,d).

son_in_law(X,Y):-
    child(X,Z),
    not(child(X,Y)),
    married(Z,Y),
    male(X).

son_in_law(f,i).

step_daughter(X,Y):-
    child(X,Z),
    married(Z,Y),
    not(child(X,Y)),
    female(X).

step_daughter(d,i).

step_parent(X,Y):-
    married(X,Z),
    parent(Z,Y),
    not(parent(X,Y)).

step_father(X,Y):-
    step_parent(X,Y),
    male(X).

step_mother(X,Y):-
    step_parent(X,Y),
    female(X).

step_mother(d,i).

uncle(X,Y):-
    sibling(X,Z),
    parent(Z,Y),
    male(X).

uncle(s1,i).

现在我在循环定义方面遇到了很多麻烦,所以在运行查询时我会陷入无限循环:祖父(i,i)。

例如,我有:

(1 毫秒) 是 {trace} | ?-祖父(i,i)。1 1 呼叫:祖父(i,i) ?
2 2 呼叫:祖父母(i,i)?
3 3 呼叫:父母(i,_103)?
4 4 呼叫:child(_127,i) ?
5 5 呼叫:父母(i,_151)?
6 6 调用:child(_175,i) ?
7 7 呼叫:父母(i,_199)?
8 8 调用:child(_223,i) ?
9 9 呼叫:父母(i,_247)?
10 10 调用:child(_271,i) ?
11 11 呼叫:父母(i,_295)?
12 12 呼叫:孩子(_319,i)?
13 13 呼叫:父母(i,_343)?
14 14 呼叫:child(_367,i) ?
15 15 呼叫:父母(i,_391)?
...

这是因为 child 将自己定义为有一个 parent,而 parent 定义自己有一个 child(正如您将在我发布的上述谓词中看到的那样)。

谁能帮我重新定义这些关系的谓词,以便我可以确定我是否是我自己的爷爷?

4

4 回答 4

6

我删除了您代码中不必要的所有内容并更改了一些内容,这就是我最终得到的结果:

% married(Husband, Wife)
married(i,w).
married(f,d).

有人会假设married(X,Y) :- married(Y,X),但它会导致讨厌的循环证明,所以我们将按照惯例将丈夫放在第一位。

关于为人父母,也会出现类似的问题。我们需要将继父母视为真正的父母,因为谜语取决于它。我们知道你永远不可能成为你自己的生物祖先!

但是,parent(X,Y) :- parent(Z,Y), married(X,Z)遇到了同样的问题,所以我只是bio_parent表示亲生父母。

bio_parent(f,i).
bio_parent(w,d).
bio_parent(w,s1).
bio_parent(i,s1).
bio_parent(d,s2).
bio_parent(f,s2).

请注意,我们必须明确父母双方,因为没有办法从婚姻中得出亲生父母的身份!此外,您的规范方式有问题。你有类似的东西:

son(X,Y) :- child(X,Y), male(X).
son(a,b).

但是,Prolog 无法从这些规则中推断出child(a,b),所以你最终得到了不是孩子的儿子!这在您的代码中发生了几次。如果您源自b,请a始终陈述a为事实!乍一看,这似乎是 Prolog 的一个缺点,但事实并非如此。请记住,每个子句只是证明某个谓词的一种方式。在上面的示例中,您说每个男孩都是儿子,而且a恰好是 的儿子b。没有任何地方说成为男孩是某人成为儿子的唯一方式,但a可能只是个例外。

下一个有点罗嗦,因为我们的定义married迫使我们将继父与继母分开对待。不过,我们立即将它们统一为继父母。

step_father(X,Y) :- married(X,Z),bio_parent(Z,Y),\+bio_parent(X,Y).
step_mother(X,Y) :- married(Z,X),bio_parent(Z,Y),\+bio_parent(X,Y).
step_parent(X,Y) :- step_father(X,Y).
step_parent(X,Y) :- step_mother(X,Y).

正如我上面所说,我们需要将继父母视为父母!

parent(X,Y) :- step_parent(X,Y).
parent(X,Y) :- bio_parent(X,Y).

grandparent(X,Y):-
    parent(X,Z),
    parent(Z,Y).

你的代码中还有一些其他的错误我也删掉了,我只是给你看一些例子,你可以从中学习。

首先,这里你说女夫已婚,男夫已婚。因此,男性妻子将未婚。反之亦然,已婚的女人才叫老婆!

% wrong:
%
% married(X,Y):-
%    wife(X,Y),
%    female(X).
%
% married(X,Y):-
%    husband(X,Y),
%    male(X).
% 
% right:
% wife(X,Y) :- married(Y,X). % according to our new definition of 'married'
% husband(X,Y) :- married(X,Y).

在这里我添加了最后一行,因为您通常不认为自己是自己的兄弟姐妹:

% sibling(X,Y):-
%    parent(Z,X),
%    parent(Z,Y),
%    X \= Y. % added this

最后两个是关于错误谓词的事实。你基本上用它们覆盖了 Prolog 的推论。它们应该被扣除,而不是作为事实陈述!

% son_in_law(f,i).
% step_mother(d,i).

现在,试试这样的程序。不要惊讶:你不会是唯一一个成为他们自己的祖父母的人!;-)

于 2013-02-21T15:01:11.873 回答
4

我的序言课程已经很久很久以前但是删除呢

parent(X,Y):-
   child(Y,X).

只是用 ? 替换parent(A,B)任何child(B,A)用法 您仍然可以添加有关父母的事实,因为反向规则仍然可用 - 您也可以删除该事实,但在这种情况下,您不能再使用有关父母的任何事实,并且您必须将所有事实写成孩子(a,b)也是。

是一样的不是吗?

于 2009-09-15T22:32:53.887 回答
2

请注意,我对 Prolog 的了解很老(而且从来没有那么深)......

我认为你需要让父母(或孩子)成为主要的(不依赖于其他关系)。

child(X,Y):-
    parent(Y,X).

parent(X,Y):-
    child(Y,X).

可能是导致循环的原因。

于 2009-09-15T22:37:24.850 回答
0

这是事实和规则

couples(i,w).
mother_of(w,d).
father_of(f,i).
couples(f,d).
son_in_law(f,i).
mother_of(d,i).
mother_of(w,s1).
mother_of(d,s2).
grand(F,C):- son_in_law(F,C),couples(H,D),mother_of(D,C).
grand(F,C):- father_of(F,D),father_of(D,C).

询问

?-grand(i,i).
于 2017-08-12T17:36:36.130 回答