Algunos antecedentes primero. Actualmente estoy aprendiendo algunas cosas sobre los combinadores de analizadores monádicos. Mientras trataba de transferir la función 'chainl1' de this paper (Pág. 16-17), se me ocurrió con esta solución:Funciones recursivas en expresiones de cálculo
let chainl1 p op = parser {
let! x = p
let rec chainl1' (acc : 'a) : Parser<'a> =
let p' = parser {
let! f = op
let! y = p
return! chainl1' (f acc y)
}
p' <|> succeed acc
return! chainl1' x
}
probé la función con alguna entrada grande y tiene un StackOverflowException. Ahora me pregunto, ¿es posible volver a escribir una función recursiva, que utiliza alguna expresión de cálculo, de modo que esté usando la recursividad de cola?
Cuando amplío la expresión de cálculo, no puedo ver cómo sería generalmente posible.
let chainl1 p op =
let b = parser
b.Bind(p, (fun x ->
let rec chainl1' (acc : 'a) : Parser<'a> =
let p' =
let b = parser
b.Bind(op, (fun f ->
b.Bind(p, (fun y ->
b.ReturnFrom(chainl1' (f acc y))))))
p' <|> succeed acc
b.ReturnFrom(chainl1' x)))
Esto elimina la recursión a través del código de usuario, pero en mi implementación aquí http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!1772.introduce StackOverflows a través de la propia implementación del analizador. Ahora estaré motivado para investigar 'analizadores sintácticos con continuaciones' ... – Brian
¿Funciona FParsec http://www.quanttec.com/fparsec/? – Brian
Brian, también usé tu serie de blog como fuente de aprendizaje. Ayudó mucho. Mientras tanto, comparé la respuesta de Mau ('seq') con mi analizador sintáctico. Y creo que el método Delay en la mónada es importar. Pero realmente no lo sé. FParsec usa 'while' ... pero quiero usar una solución funcional: D – PetPaulsen