2010-07-09 29 views
6

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 

Respuesta

14

me temo que usted podría estar recibiendo StackOverflowException debido a que se está ejecutando el programa en modo de depuración con la generación de llamada final discapacitados. Si va a Propiedades del proyecto, puede encontrar casilla de verificación Generar llamadas de cola en la pestaña Compilación. Cuando creo un nuevo proyecto, puedo reproducir el comportamiento, pero después de marcar esta opción, funciona bien (incluso para un número mucho mayor de iteraciones).

La razón por la que las llamadas finales están deshabilitadas por defecto en el modo Depuración es que dificulta mucho más la depuración (si una llamada se realiza como una llamada final, no la vería en la pila de llamadas ventana)

Esto sería una razón muy tonta para el error ... lo siento, me olvidé de mencionar esto cuando lo preguntaste antes!

+0

Tan fácil, cuando en realidad lo sepas: D ¡Gracias! Ahora está funcionando. – PetPaulsen