7

前の質問で、末尾再帰を使用するように計算式を書き直す方法を説明しました。コードを書き直しましたが、StackOverflowExceptionが発生しました。問題を特定するために、状態モナド(このブログエントリから取得)を使用していくつかの小さなコードを記述しました。

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

Loop関数は末尾再帰(?)を使用できますが、これによりStackOverflowExceptionが再びスローされます。StateBuilderクラスに何か問題があると思います。私はDelayメソッドで何かをしようとしました。すべてを余分なラムダでラップしますが、成功しません。私は現時点で完全に立ち往生しています。ここで私の2番目の試み(コンパイルされません):

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
4

1 に答える 1

15

StackOverflowException末尾呼び出しの生成が無効になっているデバッグモードでプログラムを実行しているため、取得している可能性があります。プロジェクトのプロパティに移動すると、[ビルド]タブの[末尾呼び出しの生成]チェックボックスが表示されます。新しいプロジェクトを作成すると、動作を再現できますが、このオプションをチェックすると、正常に機能します(反復回数がはるかに多い場合でも)。

デバッグモードで末尾呼び出しがデフォルトで無効になっている理由は、デバッグが非常に困難になるためです(呼び出しが末尾呼び出しとして実行された場合、[呼び出しスタック]ウィンドウには表示されません) 。

これはエラーのかなりばかげた理由です...あなたが以前に尋ねたときに私がこれについて言及するのを忘れてすみません!

于 2010-07-09T20:17:50.163 に答える