尾調用 (Tail Call)

recursive 的過程中可能會不斷堆疊記憶體,如果處理不當,就會造成 Stack Overflow,導致程式崩潰。一個新手常見的錯誤:只要是使用遞迴寫法,當遞回的次數夠多,就一定會造成 Stack Overflow。其實只要遞回符合 tail call 的規範,就可以避免使用過量記憶體的情況發生。

什麼是 tail call?簡單來說,當我們在目前的函式呼叫下一個函式時,只要不會再使用到目前函式的資源,這樣的呼叫方式就稱為 tail call。以下三個呼叫 g(x) 的方法,都不符合 tail call 規範,因為都還必須使用到當前函式的資源,因此當前函式並不會重記憶體堆疊中移除。

return g(x) + 1     -- must do the addition
return x or g(x)    -- must adjust to 1 result
return (g(x))       -- must adjust to 1 result

以下的函式也不符合 tail call,因為 g(x) 執行完還需要執行 return

function f (x)
  g(x)
  return
end

在lua 中,只有 return g(...) 才符合 Tail Call 的定義,注意新手常犯的錯誤:沒有 return 是不符合的。符合 tail call 的遞回累加函式寫法:

local function tailed_sum(n, result)
  --collectgarbage()
  --print(collectgarbage("count"))
  if n == 1 then
    return result + 1
  end
  result = result + n
  return tailed_sum(n-1, result)
end

print(sum(10))
print(tailed_sum(10, 0))

results matching ""

    No results matching ""