SWI-Prolog中的无限递归

Infinite recursion in SWI-Prolog

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

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

这是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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

当我写作时

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

而不是

1
2
3
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))).

我得到

1
2
3
4
5
?- cousin(miguelin, daniel).
false.

?- cousin(cristina, daniel).
true .

这是有效的结果。但是,当我介绍右边的递归定义时,如第一个(大)代码中所述,如果说y的表亲后代也是y的表亲,那么程序就会崩溃:

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

我不明白为什么。如果我看图像,那么递归定义(至少对我来说)是有意义的,并且miguelin现在应该是daniel的表亲(因为他是daniel的另一个表亲的后代,也就是cristina的后代)。我还"手动"测试了它,得到了正确的结果:

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

这个定义有什么问题?


cousin/2谓词的一个问题是,递归发生在解决descendant/2之前,而cousin/2在此上下文中有无限递归问题。作为一种简单的修复方法,您可以交换它们。另外,您还有一个多余的递归子类。因此,修改后的cousin/2谓词为:

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

然后你会得到:

1
2
3
4
5
6
7
8
9
?- cousin(miguelin, daniel).
true ;
false.

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

?-