2009-05-23 14 views
7

prendere questo codice di esempio (ignorare che sia terribilmente inefficiente per il momento)ricorsivi lambda in 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 "" 

Si tratta di un modello comune Continuo a imbattersi in F #, ho bisogno di avere una funzione interna che si recurses su un certo valore - e ho bisogno di questa funzione solo una volta, c'è in ogni modo possibile chiamare un lambda da sé (qualche parola chiave magica o qualcosa del genere)? Vorrei il codice per essere simile a questa:

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 "" 

Ma, come ci si potrebbe aspettare non c'è modo di fare riferimento alla funzione anonima in sé, che è necessaria dove ho messo ## RECURSE ##

risposta

17

Sì, è possibile utilizzare il cosiddetto numero y-combinators (o fixed-point combinators). Es:

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" *) 

non so articoli F #, ma questo haskell entry potrebbe anche essere utile.

Ma: non li userei se c'è qualche alternativa - Sono abbastanza difficili da capire.

Il tuo codice (omette le annotazioni del tipo qui) è un costrutto standard e molto più espressivo.

let listToString lst = 

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

    loop "" lst 
1

Nota che, anche se si dice si utilizza la funzione solo una volta, tecnicamente si fa riferimento ad esso per nome due volte, che è il motivo per cui ha senso dare un nome.