[英]Why doesn't infinite recursion hit a stack overflow exception in F#?
我知道這與人們在詢問堆棧溢出問題時遇到的問題有些相反,但是如果我創建一個函數並按如下方式調用它,我永遠不會收到任何錯誤,並且該應用程序只是磨碎了我的核心CPU,直到我強制退出它:
let rec recursionTest x =
recursionTest x
recursionTest 1
當然我可以改變它,所以它實際上是這樣的:
let rec recursionTest (x: uint64) =
recursionTest (x + 1UL)
recursionTest 0UL
這樣我可以偶爾在我的代碼中放置一個斷點,並看到 x 的值上升得相當快,但它仍然沒有抱怨。 F# 不介意無限遞歸嗎?
您的recursionTest
函數是尾遞歸的,這意味着所有遞歸調用都發生在“尾位置”,即作為函數中的最后一個動作。 這意味着 F# 編譯器不需要為遞歸調用分配新的堆棧幀,因此不會發生堆棧溢出。
尾遞歸是尾調用的一種特殊情況,尾調用是針對自身而不是其他函數。
通常,F# 發出 .NET 認可的尾調用指令:
http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.tailcall(v=vs.95).aspx
在某些特定的簡單情況下,例如您的情況,F# 將使用遞歸的程序重寫為使用循環的等效程序。
這是尾調用優化的一個示例,因此編譯器將其優化為一個簡單的循環。 請參閱: https : //devblogs.microsoft.com/fsharpteam/tail-calls-in-f/
嘗試這樣的事情:
let rec recursionTest x =
recursionTest x + recursionTest (x * 2)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.