代码之家  ›  专栏  ›  技术社区  ›  PetPaulsen

递归计算表达式

  •  6
  • PetPaulsen  · 技术社区  · 16 年前

    previous question 我被告知如何重写我的计算表达式,以便它使用尾部递归。我重写了我的代码,但仍然得到了StackOverflowException。为了定位问题,我使用状态单子(取自 this blog entry

    type State<'a, 's> = State of ('s -> 'a * 's)
    
    let runState (State s) initialState = s initialState
    
    let getState = State (fun s -> (s,s))
    let putState s = State (fun _ -> ((),s))
    
    type StateBuilder() =
      member this.Return a = State (fun s -> (a, s))
      member this.Bind(m, k) = 
        State (fun s -> let (a,s') = runState m s in runState (k a) s')
      member this.ReturnFrom a = a
    let state = new StateBuilder()
    
    let s max = 
        let rec Loop acc = state {
            let! n = getState
            do! putState (n + 1)
            if acc < max then
                return! Loop (acc + 1)
            else return acc
            }
        Loop 0
    
    runState (s 100000) 0
    

    这将再次抛出StackOverflowException,尽管循环函数可以使用尾部递归(?)。我想国家建设者班出了点问题。我试着用延迟法做些什么。把所有东西都包在一个额外的lambda里,没有成功。

    type State<'a, 's> = State of ('s -> 'a * 's)
    
    let runState (State s) initialState = s initialState
    
    let getState = fun () -> State (fun s -> (s,s))
    let putState s = fun () -> State (fun _ -> ((),s))
    
    type StateBuilder() =
      member this.Delay(f) = fun () -> f()
      member this.Return a = State (fun s -> (a, s))
      member this.Bind(m, k) = 
        fun () -> State (fun s -> let (a,s') = runState (m ()) s in runState ((k a) ()) s')
      member this.ReturnFrom a = a
    let state = new StateBuilder()
    
    let s max = 
        let rec Loop acc = state {
            let! n = getState
            do! putState (n + 1 - acc)
            if acc < max then
                return! Loop (acc + 2)
            else return acc
            }
        Loop 0
    
    runState (s 100000 ()) 0
    
    1 回复  |  直到 9 年前
        1
  •  15
  •   Tomas Petricek    16 年前

    我担心你可能会 StackOverflowException 因为您正在调试模式下运行程序,并且禁用了尾部调用生成。如果转到“项目属性”,则可以找到 生成尾部调用 上的复选框 建造 选项卡。当我创建一个新的项目时,我可以复制行为,但是在选中这个选项之后,它工作得很好(即使迭代次数要大得多)。

    调用堆栈 窗口)

    这将是一个相当愚蠢的错误原因。。。对不起,你刚才问我的时候我忘了提这个!