2009-05-23 21 views
7

Tome este código de ejemplo (ignorarlo siendo terriblemente ineficiente por el momento)lambdas recursivas en F #

let listToString (lst:list<'a>) = ;;' prettify fix 

    let rec inner (lst:list<'a>) buffer = ;;' prettify fix 
     match List.length lst with 
     | 0 -> buffer 
     | _ -> inner (List.tl lst) (buffer + ((List.hd lst).ToString())) 

    inner lst "" 

Este es un patrón común que repetidamente encontramos en Fa #, tengo que tener una función interna que recursivamente propio sobre algún valor, y solo necesito esta función una vez, ¿hay alguna forma de llamar a una lambda desde su interior (alguna palabra clave mágica o algo así)? Me gustaría que el código a ser algo como esto:

let listToString2 (lst:list<'a>) = ;;' prettify fix 

    (fun 
     (lst:list<'a>) buffer -> match List.length lst with ;;' prettify fix 
           | 0 -> buffer 
           | _ -> ##RECURSE## (List.tl lst) (buffer + ((List.hd lst).ToString())) 
    ) lst "" 

Pero como era de esperar no hay manera de hacer referencia a la función anónima dentro de sí mismo, que es necesaria donde pongo ## RECURSE ##

Respuesta

17

Sí, es posible usar el llamado y-combinators (o fixed-point combinators). Ej:

let rec fix f x = f (fix f) x 

let fact f = function 
| 0 -> 1 
| x -> x * f (x-1) 


let _ = (fix fact) 5 (* evaluates to "120" *) 

no sé artículos F # pero esto haskell entry también podría ser útil.

Pero: no los usaría si hubiera alguna alternativa: son bastante difíciles de entender.

Su código (omita las anotaciones de tipo aquí) es una construcción estándar y mucho más expresiva.

let listToString lst = 

    let rec loop acc = function 
     | [] -> acc 
     | x::xs -> loop (acc^(string x)) xs 

    loop "" lst 
1

en cuenta que aunque usted dice que utiliza la función de una sola vez, técnicamente se refieren a ella por su nombre dos veces, por lo que tiene sentido para darle un nombre.