2011-10-17 90 views
1

我不認爲我瞭解遞歸在序言中是如何工作的遞歸在序言

下面的代碼(冪函數)

pow(_,0,1). 
pow(X,Y,Z) :- 
    Y1 is Y - 1 , 
    pow(X,Y1,Z1) , 
    Z is Z1*X 
    . 

創建以下跟蹤:

[trace] ?- pow(2,2,X). 
    Call: (6) pow(2, 2, _G368) ? creep 
    Call: (7) _G444 is 2+ -1 ? creep 
    Exit: (7) 1 is 2+ -1 ? creep 
    Call: (7) pow(2, 1, _G443) ? creep 
    Call: (8) _G447 is 1+ -1 ? creep 
    Exit: (8) 0 is 1+ -1 ? creep 
    Call: (8) pow(2, 0, _G446) ? creep 
    Exit: (8) pow(2, 0, 1) ? creep 
    Call: (8) _G450 is 1*2 ? creep 
    Exit: (8) 2 is 1*2 ? creep 
    Exit: (7) pow(2, 1, 2) ? creep 
    Call: (7) _G368 is 2*2 ? creep 
    Exit: (7) 4 is 2*2 ? creep 
    Exit: (6) pow(2, 2, 4) ? creep 

我不明白最後的狀態如何:'Z是Z1 * X'的作品。這個函數何時被調用?當達到基本情況時? 基礎案例如何被調用?

感謝

+0

在第一條順便說一句,你的戰俘丟失晉級。寫入它的方式會陷入無限遞歸中,如果您指示prolog在找到第一個解決方案後嘗試找到更多解決方案。 –

回答

1

你可以把pow想象成一個函數,它被分成了兩個處理不同參數值的子句。該函數是遞歸的,這是由第二個子句中的遞歸調用觸發的。但是在這次通話之後,還有一些事情要做,即目標Z is Z1*1。這些「搖擺」的計算是在遞歸結束時完成的,並在可以這麼說的時候再次控制「氣泡」向上。 (這是一種我不記得的遞歸名稱)。

看這個評論跡:

[trace] ?- pow(2,2,X). 
     % initial call 
    Call: (6) pow(2, 2, _G368) ? creep 
     % the second clause is picked for this call, 
     % the third argument is an uninstantiated variable, represented by _G368 
    Call: (7) _G444 is 2+ -1 ? creep 
     % the first goal in this claus is "Y1 is Y -1", which is here 
     % translated with its bindings 
    Exit: (7) 1 is 2+ -1 ? creep 
     % the is/2 goal has been called, and has provided a binding for "Y1" 
    Call: (7) pow(2, 1, _G443) ? creep 
     % this is the first recursive call, with the new arguments 2, 1 and an 
     % undefined Z1 
    Call: (8) _G447 is 1+ -1 ? creep 
     % again the second clause is used, this is the first goal in it, 
     % calling is/2 
    Exit: (8) 0 is 1+ -1 ? creep 
     % is/2 delivers a binding for the current Y1, 0 
    Call: (8) pow(2, 0, _G446) ? creep 
     % the next (second) recursive call; see how at this point non of the 
     % "Z is Z1*X" "statements" have been reached 
    Exit: (8) pow(2, 0, 1) ? creep 
     % the second recursive call matches the first clause; this is where 
     % the base case is used! it can immediately "Exit" as with the match 
     % to the clause all bindings have been established already; the third 
     % argument is instantiated to 1 
    Call: (8) _G450 is 1*2 ? creep 
     % now the recursion has terminated, and control is passed back to that 
     % more recent calling clause (this was the one where Y1 has been bound 
     % to 0); now the "Z is Z1*X" can be tried for the first time, and Z 
     % can be instantiated ("unified") 
    Exit: (8) 2 is 1*2 ? creep 
     % this is the result of this unification, Z is bound to 2; 
     % with this, this level in the stack of recursive calls has been completed... 
    Exit: (7) pow(2, 1, 2) ? creep 
     % ... and this is the result ("Exit") of this call, showing all 
     % instantiated parameters 
    Call: (7) _G368 is 2*2 ? creep 
     % but this just brings us back one more level in the call stack, to a 
     % pending execution (this was the one where Y1 has been bound to 1), 
     % now the pending execution can be performed 
    Exit: (7) 4 is 2*2 ? creep 
     % here you see the result of the execution of is/2, binding Z to 4 
    Exit: (6) pow(2, 2, 4) ? creep 
     % and this finishes the initial call of the predicate, delivering a 
     % binding for the X in the query, 4; you can tell that the recursive 
     % call stack as been processed completely by looking at the "stack 
     % depth indicator", (6), which matches the initial (6) when the trace 
     % started (they don't necessarily start with 0 or 1). 
+0

非常感謝,非常感謝 –

+1

我想我明白了,但還是有點不清楚,爲什麼_G446實例化爲1?因爲其他兩個參數與事實相符,並且最後一個參數'_G446'沒有實際意義?如果是這樣,那我明白了!再次感謝您的解釋 –

+0

*「因爲還有其他兩個參數符合事實,最後一個參數'_G446'沒有實際意義嗎?」* - 確切地說。 – ThomasH

1

與星號(*)的跟蹤每一行使用 「Z是Z1 * X」 的規則。

此代碼的工作通過提供功率函數的以下遞歸定義:

  1. X^0 = 1對於所有X.
  2. X^Y = X ^(Y-1)* X

Z,Z1和Y1變量是Prolog需要一種方式來引用中間結果的事實的假象;你叫Y-1 Y1,你叫X ^(Y-1)Z1。

這通過在遞歸的每個級別將指數(Y)減1(產生Y1)直到Y = 0並且定義的第一種情況適用,從而得到基本情況。

+1

基本情況下的最後一個參數如何? POW(_,0,1)。我明白第一個參數是匿名的,所以我們不關心它,第二個參數很明顯,但我不明白'1'是如何達到的。謝謝! –

+1

pow(X,0,1)是事實。這意味着,無論你採取0的權力產生1. 如果你只使用這個事實,你可以問prolog問題,如:pow(48,0,X)。它會回答X = 1 –

2

重點是pow不是函數。這是一個謂詞。 Prolog並沒有真正評估pow,它試圖滿足其條件。

何時達到第一個條款?每次都嘗試過。但是除非第二個參數是0並且第三個參數是1(或者它們是可以與這些值統一的變量),否則它會失敗。當第一個條款失敗時,第二個條款被嘗試。

+0

非常感謝,但我意識到我的主要問題是理解何時達到最後一個參數(Z)。你能詳細說明一下嗎? –

+0

假設你輸入類似'pow(2,3,Res)'的東西。第一個條款顯然是錯誤的(3!= 0)。當第二個子句被嘗試時,首先計算變量'Y1'。然後遞歸地使用'pow',將值賦給'Z1'。最後,計算'Z'的值。 – svick