我怎样才能在Prolog中实现“我是我自己的爷爷”?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我怎样才能在Prolog中实现“我是我自己的爷爷”?相关的知识,希望对你有一定的参考价值。

以下故事来自N. Wirth(1976)Algorithms + Datastructures = Programs。

我娶了一个寡妇(让我们称她为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} | ? - 祖父(我,我)。 1 1电话:爷爷(我,我)? 2 2电话:祖父母(i,i)? 3 3电话:家长(i,_103)? 4 4电话:孩子(_127,i)? 5 5电话:家长(i,_151)? 6 6电话:孩子(_175,i)? 7 7电话:家长(i,_199)? 8 8电话:孩子(_223,i)? 9 9电话:家长(i,_247)? 10 10电话:孩子(_271,i)? 11 11致电:家长(i,_295)? 12 12电话:孩子(_319,i)? 13 13致电:家长(i,_343)? 14 14电话:孩子(_367,i)? 15 15电话:家长(i,_391)? ...

这是因为child将自己定义为拥有父级,而父级定义自己拥有子级(正如您在上面发布的谓词中所看到的那样)。

任何人都可以帮助我重新定义我对这些关系的谓词,以便我可以确定我是不是自己的爷爷?

答案

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

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

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

另一答案

我的prolog课程已经很久很久了,但是去除了

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

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

这是不一样的吗?

另一答案

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

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

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

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

是什么可能导致循环。

另一答案

这是事实和规则

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

以上是关于我怎样才能在Prolog中实现“我是我自己的爷爷”?的主要内容,如果未能解决你的问题,请参考以下文章

在Python中实现Prolog统一算法?回溯

我怎样才能在每个单元格中实现这种类型的渐变?

我有一个 MYSQL 表创建查询,其中包含以下约束 KEY `ix_email_address` (`address`) 。我怎样才能在蜂巢中实现这个?

Prolog中的双向链表

在 prolog 中编译元程序时出错

在OpenGL中实现边界球碰撞