在Frege中優化了尾部調用。我知道在Java或者編譯爲像Clojure和Scala這樣的JVM字節碼的語言中都沒有TCO。弗雷格呢?Frege是否執行尾部呼叫優化?
回答
Frege通過簡單地生成while循環來進行尾遞歸優化。
通用尾部呼叫通過懶惰來「處理」。如果編譯器看到對已知(間接)遞歸的可疑函數的尾調用,則會返回一個延遲結果(一個thunk)。因此,調用該函數的真正負擔在於調用者。這樣,可以避免深度依賴於數據的堆棧。這就是說,靜態堆棧深度在功能語言中本來就比Java更深。因此,有些程序需要更大的堆棧(即使用-Xss1m)。
有病態的情況下,大thunk被建立,當他們被評估,會發生堆棧溢出。一個臭名昭着的例子是foldl函數(與Haskell中的問題相同)。因此,Frege中的標準左摺疊是fold,它是累加器中的尾遞歸和嚴格的,因此在常量堆棧空間中工作(如Haskells foldl')。
下面的程序應該不堆棧溢出,但打印「假」後2分或3秒:
module Test
-- inline (odd)
where
even 0 = true
even 1 = false
even n = odd (pred n)
odd n = even (pred n)
main args = println (even 123_456_789)
這種工作方式如下:的println必須有一個值來打印,所以試圖評估(偶數n )。但它所得到的僅僅是(奇數(pred n))。因此,它試圖評估這個thunk,從而得到另一個thunk(甚至(pred(pred n)))。甚至必須在返回其中已經評估了n-2的另一個thunk(odd(pred(n-2))之前必須評估(pred(pred n))以查看參數是0還是1 這樣,所有調用在JVM級別)是從println內部完成的,在任何時候甚至都不會調用奇數,反之亦然。
如果取消註釋內聯指令,則得到even的尾遞歸版本,並且結果獲得10倍。更快
不用說,這種笨拙的算法是僅用於演示 - 通常一個會檢查甚至岬有位操作
這裏是另一個版本,那就是病態的,將堆棧overflo女:
even 0 = true
even 1 = false
even n = not . odd $ n
odd = even . pred
的問題在這裏,not
是尾調用,它是在它的參數嚴格(即否定的東西,你必須先有一個東西)。因此,當計算even n
時,則not
必須完全評估odd n
,而這又必須完全評估even (pred n)
,因此需要2 * n個堆棧幀。
不幸的是,即使JVM應該有一天有適當的尾部呼叫,這也不會改變。原因是嚴格函數論證中的遞歸。
令人驚歎的答案,非常感謝!順便說一下弗雷格有嚴格的註釋嗎? – haskelline 2012-04-05 19:03:36
是的。爆炸模式。 – Ingo 2012-04-05 19:13:26
@Landei TCO在Scala中完全不支持...試試這個。
def foo() { def bar() { println("bar"); foo() }; println("foo"); bar() }
請注意,我沒有足夠的信譽來直接發表評論。查找評論我在原始問題的評論中回覆。
- 1. MATLAB是否執行尾部呼叫優化?
- 2. 尾部呼叫優化javascript
- 3. Rebol尾部呼叫優化
- 4. 是否可以強制執行GCC/Clang上的尾部呼叫優化?
- 5. 尾部呼叫優化是否適用於遞歸調用以外的呼叫?
- 6. F#中的尾部呼叫優化#
- 7. lua的尾部呼叫優化
- 8. Mono/Ironpython中的尾部呼叫優化
- 9. array_walk_recursive是否使用尾部呼叫優化?
- 10. NVCC和NVRTC是否支持尾部呼叫優化?
- 11. C尾呼叫優化
- 12. 這是否被視爲尾部呼叫?
- 13. 爲什麼scala不會進行尾部呼叫優化?
- 14. 教堂是否實施尾巴呼叫優化?
- 15. Visual C++尾巴呼叫優化
- 16. 尾巴呼叫優化球拍
- 17. 當執行時,這將是一個尾部呼叫?
- 18. 是尾巴呼叫優化所有解釋此性能差異
- 19. '聰明'是GCC的尾巴呼叫優化?
- 20. Arduino是否支持尾部呼叫消除?
- 21. Clojure中的尾部呼叫消除?
- 22. Node.js尾部優化:可能與否?
- 23. C#優化器是否執行copy elision?
- 24. Delphi編譯器是否執行優化?
- 25. 編譯優化呼叫-RET VS JMP
- 26. PHP是否優化尾遞歸?
- 27. 功能/回調執行是否可以被外部呼叫中斷?
- 28. 黑客尾部優化
- 29. 使用最終工作流程時,缺少尾部呼叫優化是一個障礙嗎?
- 30. curl_multi_exec()是否阻塞呼叫?
問題的標題是人們看到的第一個東西,而「TCO」只是另一個TLA。 – 2012-04-04 09:58:59
應該指出的是,Scala擁有TCO,而且一些JVM(如IBM的)也實現了它。 – Landei 2012-04-06 10:20:12
@Landei這是Scala中的一項新功能嗎?長期以來,Scala一直不支持TCO! – haskelline 2012-04-12 13:39:51