2014-03-29 47 views
2

我试图定义一个家族树及其节点之间的关系,它们的定义基于三个谓词:male/1,female/1parent_of/2SWI-Prolog中的无限递归

我已经定义尊亲属,后裔,父亲,母亲,儿子,女儿,爷爷,奶奶,姑姑,叔叔和表哥的概念。任何新的定义都不能基于“兄弟/姐妹”的概念,而只能基于以前的定义。

这是代码:

male(daniel). 
male(miguelangel). 
male(mario). 
male(mahmoud). 
male(esteban). 
male(enrique). 
male(javier). 
male(miguelin). 

female(diana). 
female(hengameh). 
female(vicenta). 
female(mahvash). 
female(angeles). 
female(mexicana). 
female(eloina). 
female(esmeralda). 
female(cristina). 
female(otilia). 

parent_of(miguelangel, daniel). 
parent_of(miguelangel, diana). 
parent_of(hengameh, daniel). 
parent_of(hengameh, diana). 
parent_of(mario, miguelangel). 
parent_of(mario, esteban). 
parent_of(mario, eloina). 
parent_of(mario, angeles). 
parent_of(mario, otilia). 
parent_of(vicenta, miguel). 
parent_of(vicenta, esteban). 
parent_of(vicenta, eloina). 
parent_of(vicenta, angeles). 
parent_of(vicenta, otilia). 
parent_of(mahmoud, hengameh). 
parent_of(mahvash, hengameh). 
parent_of(enrique, javier). 
parent_of(angeles, javier). 
parent_of(cristina, miguelin). 
parent_of(otilia, cristina). 
parent_of(eloina, esmeralda). 

% Rules 

ancestor(X, Y) :- 
    parent_of(X, Y); 
    parent_of(X, Z), 
    ancestor(Z, Y). 

descendant(X, Y) :- 
    ancestor(Y, X). 

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

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

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

daughter(X, Y) :- 
    parent_of(Y, X), 
    female(X). 

grandfather(X, Y) :- 
    parent_of(X, Z), 
    parent_of(Z, Y), 
    male(X). 

grandmother(X, Y) :- 
    parent_of(X, Z), 
    parent_of(Z, Y), 
    female(X). 

aunt(X, Y) :- 
    (grandfather(Z, Y) ; grandmother(Z, Y)), 
    (father(Z, X) ; mother(Z, X)), 
    not(parent_of(X, Y)), 
    female(X). 

uncle(X, Y) :- 
    (grandfather(Z, Y) ; grandmother(Z, Y)), 
    (father(Z, X) ; mother(Z, X)), 
    not(parent_of(X, Y)), 
    male(X). 

cousin(X, Y) :- 
    ((uncle(Z, Y), parent_of(Z, X)) ; (cousin(P, Y), descendant(X, P)));  
    ((aunt(Z, Y), parent_of(Z, X)) ; (cousin(P, Y), descendant(X, P))). 

为了清楚起见,我已经通过图像代表树的一部分在那里我有问题:

enter image description here

当我写

cousin(X, Y) :- 
    ((uncle(Z, Y), parent_of(Z, X))); 
    ((aunt(Z, Y), parent_of(Z, X))). 

而不是

cousin(X, Y) :- 
    ((uncle(Z, Y), parent_of(Z, X)) ; (cousin(P, Y), descendant(X, P)));  
    ((aunt(Z, Y), parent_of(Z, X)) ; (cousin(P, Y), descendant(X, P))). 

我得到

?- cousin(miguelin, daniel). 
false. 

?- cousin(cristina, daniel). 
true . 

这是有效的结果。但是,当我介绍右边的递归定义,第一个(大)代码表示,这么说Y的堂兄弟的后代也是Y的表兄弟,程序崩溃:

?- cousin(miguelin, daniel). 
ERROR: Out of local stack 

我不明白为什么。如果我看的图像,这是有道理的(至少我)递归定义,并miguelin现在应该是daniel表弟(因为他是daniel另一个表弟,这是cristina的后代)。我也对它进行了“手动”测试,并得到了正确的结果:

?- cousin(cristina, daniel), descendant(X, cristina). 
X = miguelin ; 

定义有什么问题?

回答

1

cousin/2谓词的一个问题是递归发生在您解决descendant/2之前,并且cousin/2在此上下文中具有无限递归问题。作为解决这个问题的简单方法,你可以将它们交换。另外,你有一个冗余的递归子条款。因此,修改后的cousin/2谓语是:

cousin(X, Y) :- 
    (uncle(Z,Y), parent_of(Z,X)) ; 
    (aunt(W,Y), parent_of(W,X)) ; 
    (descendant(X,P), cousin(P,Y)). 

然后你会得到:

?- cousin(miguelin, daniel). 
true ; 
false. 

?- cousin(cristina, daniel). 
true ; 
false. 

?- 
+0

哦,我明白了。我忘记了,尽管在逻辑中由一个连接词连接的两个谓词的顺序并不重要,但在Prolog中,由于它所运行的机器的性质,这很重要。感谢您帮助我:) –

+0

@DanielMuñozParsapoormoghadam从技术上说,您是正确的:逻辑上,谓词应该按原样工作。然而,“堂兄”有一个循环逻辑问题,我首先考虑了“后代”,从而缩小了“堂兄”的选项。它也使谓词尾递归。通过一些其他重写,可以使查询“正式”第一次正常工作。但是我展示的是最简单的方法。我重新回答了我的答案以反映这一点。 – lurker