En un previous question me dijeron cómo volver a escribir mis expresiones de cálculo para que use recursividad de cola. Reescribí mi código pero todavía recibí una StackOverflowException. Para localizar el problema que escribí algo de código pequeño usando una mónada estado (tomado de this blog entry):Expresiones de cálculo recursivas
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
Esta es lanzar una StackOverflowException de nuevo, aunque la función de bucle podría utilizar la recursión de cola (?). Supongo que algo está mal con la clase StateBuilder. Traté de hacer algo con el método Delay. Arreglando todo en una lambda extra, sin éxito. Estoy totalmente sorprendido en este momento. Aquí mi segundo intento (no compila):
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
Tan fácil, cuando en realidad lo sepas: D ¡Gracias! Ahora está funcionando. – PetPaulsen