2013-06-22 58 views
7

在SICP Section 1.2.1提交給諸如下面的代碼實例來說明如何使用迭代過程來解決階乘問題:SICP遞歸過程VS迭代過程:使用遞歸過程來生成一個迭代過程

(define (factorial n) 
    (fact-iter 1 1 n)) 
(define (fact-iter product counter max-count) 
    (if (> counter max-count) 
     product 
     (fact-iter (* counter product) 
       (+ counter 1) 
       max-count))) 

並且說「看起來令人不安的是,我們將一個遞歸過程(例如fact-iter)稱爲生成一個迭代過程。然而,這個過程確實是迭代的:它的狀態完全被它的三個狀態變量捕獲,並且解釋器需要跟蹤只有三個變量才能執行該過程。「

我不明白作者的意思。遞歸過程和遞歸過程有什麼區別?爲什麼他說下面的遞歸過程產生一個迭代過程?

回答

10

A 遞歸過程需要在遞歸調用過程中保持調用者的狀態。舉例來說,如果你寫:

(define (fact-recurse n) 
    (if (< n 2) 
     1 
     (* n (fact-recurse (- n 1))))) 

外通話必須記住n,等待內部調用返回,然後才能執行乘法。如果調用(fact-recurse 10),則當函數達到其遞歸結束時,會有9個堆棧乘法等待處理。

但是在迭代過程中,較早的狀態可以被丟棄。這在示例代碼中是可行的,因爲所有需要的信息在遞歸調用中作爲參數傳遞。外部調用中的變量不再需要,因此不需要在堆棧上保留任何內容。

由於外部調用的參數不再需要,遞歸調用可以翻譯成分配:

(set! product (* counter product)) 
(set! counter (+ counter 1) 
(set! max-count max-count) 

,然後它只是跳轉到過程的開始。

+0

明白了,非常感謝。 – zuozuo

+0

這是所有可以進行呼叫優化的地方,堆棧不再需要,可以丟棄,正確嗎? –

+1

@JonSurrell準確無誤。引用的內容解釋了尾部呼叫優化是如何發生的。 – Barmar