2014-03-29 95 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