Tailing Recursion是大部分Function Language的基本配備,在沒有迴圈的情況下,Recursive是唯一的方案。
而Tailing Recursion是Tail Call的一種特例。只是最後呼叫的函數是自己。
在不討綠用公式解跟迴圈解的情況下,要從1加到1000000000我們會這麼寫。
1 | long long sum(int n) |
這段程式在Visual C++會掛,而在GCC跟Clang可以正常運作。 (Visual C++的判別還真有點弱)。
不過我想說的是後面這個,Tailing Recursion Optimization
。
跟上面很類似,不過會多帶一個參數,代表初始狀態。
上面的範例可以重新寫成
1 | long long int sum(int n, long long int v) |
這種寫法比上面好的點,在於當我們要做Recursive呼叫的時候,必須保留呼叫時每一層的狀態,存在Stack裡,當你遞迴深度過深時,超過OS給予的極限,就會造成Stackoverflow。而用下面這種寫法的話,則不需要保留遞迴中的堆疊。只需要修改當前堆疊的值,然後既需呼叫函式即可。
還有如果把之後要做的事情當做參數傳進來,就變成Continuation-passing style了。
把程式碼改寫成這樣
1 | void sum(int n, long long int v, function<void (long long)> contWith) |
結果所有編譯器全掛了,同樣邏輯的程式碼用Haskell重寫一次
1 | sum' n total cont |
整個計算資源被耗盡了,難道1000000000真的玩太大了。