繁体   English   中英

F# 中的递归堆栈溢出异常

[英]recursive stack overflow with exceptions in F#

让我们看看这段代码:

let rec doSomething () =
    let d = GetSomeDataFromSomewhere()
    match d with
    | Some x -> x
    | None   -> doSomething()

所以这是某种形式的不间断轮询..

但现在是以下形式:

let rec doSomething () =
    try        
        let d = GetSomeDataFromSomewhereButItCouldCrash()
        match d with
        | Some x -> x
        | None   -> doSomething()
    with _ ->
        doSomething()

如果有很多异常,那将导致堆栈溢出。

有人可以解释一下使这两个版本表现不同的机制吗?

问题是第二个版本中的第一个调用不在尾调用 position 中。这并不完全明显,因为递归调用是“function 所做的最后一件事”,但运行时仍然必须保留堆栈帧around,因为它需要保留关联的异常处理程序。

let rec doSomething () =
    try        
        let d = GetSomeDataFromSomewhereButItCouldCrash()
        match d with
        | Some x -> x
        | None   -> doSomething() // This is not a tail call!
    with _ ->
        doSomething() // This is a tail call

如果您在调用GetSomeDataFromSomewhere时直接处理异常并将它们变成None ,那么您可以保持相同的逻辑,但使其尾部递归:

let rec doSomething () =
  let d = try GetSomeDataFromSomewhereButItCouldCrash() with _ -> None
  match d with
  | Some x -> x
  | None   -> doSomething()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM