適當的尾端遞迴

lua-users home
wiki

Lua 5.0 執行**適當的尾端遞迴** [1]。這表示對於函數的特定呼叫形式,會進行優化以節省資源,也就是堆疊。此形式會讓每個函數結束時,都回傳函數的值 (包括遞迴呼叫),而會重複使用目前的堆疊框架,而無需使用堆疊資源。使用虛擬程式碼說明

function f(args)
    ...
    return g(args2)
end

遞迴函數有時可以改寫成尾端遞迴的版本。例如,階乘函數的傳統定義會帶領我們到

function fact(n) if (n==0) then return 1 else return n*fact(n-1) end end

這不是尾端遞迴,因為最後要進行的運算,是將 nfact(n-1)相乘。但以下程式碼就是

function factt(n) return fact_(n, 1) end

function fact_(n, ans) if (n==0) then return ans else return fact_(n-1, n*ans) end end

對於相同的引數,兩個定義的結果絕對相同。

> = fact(5)
120
> = factt(5)
120
但在幕後的情境有所不同。如果我們以不符設計方式使用函數,就可以突顯這個差異。上面的基本實作僅適用於正整數。如果給予負數或分數結果,預計會偏離成無限遞迴。

如果我們執行 fact(-1),就會收到堆疊溢出的訊息

> = fact(-1)
stdin:1: stack overflow
stack traceback:
        stdin:1: in function `fact'
        stdin:1: in function `fact'
        ...
        stdin:1: in function `fact'
        (tail call): ?
        [C]: ?
另一方面,如果我們呼叫 factt(-1),它永遠不會回傳 (此為比較類似函數主體的數學分析)。

適當的尾端遞迴在於節省,這對於 Lua 所要應用於的應用程式類型非常重要。當作優化時,除錯會更為困難,因為無法重建呼叫追蹤。

每次語言規格說明已實作適當的尾端遞迴時,就表示在尾函數呼叫的特殊案例中,堆疊不會被浪費。這是語言設計者提供給使用者品質合約。在電腦科學世界中相當常見:Scheme、Perl、Forth 這些語言也這麼做。如果你的最愛程式語言沒有這麼做,那就大聲抱怨吧。

這是一個入門文字。它是要說明 Lua 功能中適當尾端遞迴這個功能,並可能在函數呼叫教學課程中提到。


RecentChanges · 偏好設定
編輯 · 記錄
最後編輯時間為 November 17, 2003 2:52 am GMT (差異)