2011-02-25 35 views
1

我正在使用swipl 5.10.2。今天我開始學習我的AI課程的Prolog。 我已經開始與一個非常簡單的例子:這是Prolog中的左遞歸嗎?

father(giovanni,maria). 
brother(paolo,pietro). 

grandpa(X,Y) :- 
     father(X,Z), 
     father(Z,Y). 
grandpa(X,Y) :- 
     father(X,Z), 
     mother(Z,Y). 

mother(maria,paolo). 
mother(I,J) :- 
     mother(I,K), 
     brother(K,J). 

不是什麼大不了的,如果我嘗試這個目標grandpa(giovanni,pietro),它的工作,這讓我真正。然後我想辣迎接挑戰,我修改這樣的代碼:

father(giovanni,maria). 
brother(paolo,pietro). 

grandpa(X,Y,Z) :- 
     father(X,Z), 
     father(Z,Y). 
grandpa(X,Y,Z) :- 
     father(X,Z), 
     mother(Z,Y). 

mother(maria,paolo). 
mother(I,J) :- 
     mother(I,K), 
     brother(K,J). 

,因爲我想知道中間人但是當我運行它這裏發生了什麼:

?- grandpa(giovanni,pietro,M). 
M = maria ; 
ERROR: Out of local stack 

這是因爲,imho,母親有一個左遞歸,樹不斷髮展而沒有發現關閉。

然後我寫了這個:

father(giovanni,maria). 
brother(paolo,pietro). 
mother(maria,paolo). 

grandpa(X,Y,Z) :- 
     father(X,Z), 
     father(Z,Y). 
grandpa(X,Y,Z) :- 
     father(X,Z), 
     mother(Z,Y). 

mother(I,J) :- 
     brother(K,J), 
     mother(I,K). 

這是輸出:

?- grandpa(giovanni,pietro,M). 
M = maria ; 
false. 

這是正確的。那麼這只是一個左遞歸問題,還是我錯過了一些關於swipl行爲的東西?當我有一個「錯誤:超出本地堆棧」,它總是一個遞歸問題?

回答

3

我認爲Out of local stack錯誤幾乎總是(或總是)來自太深的遞歸;在簡單的程序中,這些遞歸可能是無限的。代碼中的問題確實是左遞歸問題;試圖解決mother(anything, B)將嘗試解決mother(anything, B1),mother(anything, B2)等等,直到您用完堆棧空間。

+1

+1我想補充一點,最大遞歸深度根據處理的項的數量和大小而變化很大(如果涉及到列表,很容易按100倍),而* tail遞歸*是解決方案可以很大程度上避免過度使用堆棧。如果編譯器支持* tail遞歸*,則編譯器支持 – 2011-02-25 21:49:12

+0

。就像你可以用Java那樣做,但JVM不支持它,對吧? – dierre 2011-02-27 13:53:05

+1

雖然這段代碼沒有這個問題;它是一個無限遞歸,與是否使用尾調用無關(在這種情況下,對'mother'的規則中的目標進行重新排序可以解決問題)。 – 2011-02-27 21:58:40