В 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 снова, хотя функцию Loop можно использовать хвостовую рекурсию (?). Я думаю, что что-то не так с классом StateBuilder. Я пытался что-то сделать с помощью метода Delay. Сотрясать все в дополнительной лямбде, без успеха. Im полностью застрял в данный момент. Вот моя вторая попытка (не компилируется):
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
Так просто, когда вы на самом деле это знаете: D Спасибо! Теперь он работает. – PetPaulsen