簡體   English   中英

為什么無限遞歸不會在 F# 中遇到堆棧溢出異常?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM