Recursion SWI-Prolog中的无限递归

Recursion SWI-Prolog中的无限递归,recursion,prolog,family-tree,Recursion,Prolog,Family Tree,我试图根据三个谓词来定义族谱及其节点之间的关系:male/1、female/1和parent\u/2 我已经定义了上升、后代、父亲、母亲、儿子、女儿、祖父、祖母、阿姨、叔叔和堂兄弟的概念。任何新的定义都不能基于“兄弟姐妹”的概念,而只能基于以前的定义 代码如下: male(daniel). male(miguelangel). male(mario). male(mahmoud). male(esteban). male(enrique). male(javier). male(miguelin

我试图根据三个谓词来定义族谱及其节点之间的关系:
male/1
female/1
parent\u/2

我已经定义了上升、后代、父亲、母亲、儿子、女儿、祖父、祖母、阿姨、叔叔和堂兄弟的概念。任何新的定义都不能基于“兄弟姐妹”的概念,而只能基于以前的定义

代码如下:

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))).
为了清晰起见,我通过一个图像表示了我遇到问题的树的一部分:

当我写作时

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))).
我明白了

这些都是有效的结果。但是,当我在右边引入递归定义时,正如第一段(大)代码中所述,表示Y的近亲的后代也是Y的近亲,程序崩溃了:

?- cousin(miguelin, daniel).
ERROR: Out of local stack
我不明白为什么。如果我看这幅图像,递归定义(至少对我来说)是有意义的,而且
miguelin
现在应该是
daniel
的堂兄弟(因为他是
daniel
的另一个堂兄弟的后代,也就是
cristina
)。我还“手动”测试了它,得到了正确的结果:

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

定义有什么问题?

堂兄弟/2谓词的一个问题是,递归发生在解析
后代/2
之前,
堂兄弟/2
在此上下文中存在无限递归问题。作为解决这一问题的简单方法,您可以交换它们。此外,还有一个冗余的递归子类。因此,修改后的
近亲/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.

?-

哦,我明白了。我忘记了,虽然在逻辑上,两个谓词被一个连词连接的顺序并不重要,但在Prolog中,由于运行它的机器的性质,它们的顺序是重要的。谢谢你的帮助:)@DanielMuñozparsapormoghadam技术上你是对的:从逻辑上讲,谓词应该按原样工作。但是,
近亲
有一个循环逻辑问题,我先考虑了
后代
,从而缩小了
近亲
的选项范围。它还使谓词尾部递归。通过一些其他重写,可以首先使对
cosine
的查询正常工作。但我展示的是最简单的方法。我改写了我的答案以反映这一点。
?- cousin(miguelin, daniel).
true ;
false.

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

?-