2009-05-23 12 views
7

Prenez ce code par exemple (l'ignorer étant horriblement inefficace pour le moment)lambdas récursives 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 "" 

Ceci est un modèle commun que je continue à venir à travers en F #, je dois avoir une fonction intérieure qui se récursif sur une certaine valeur - et je n'ai besoin de cette fonction qu'une seule fois, est-il possible d'appeler un lambda de l'intérieur de lui-même (un mot-clé magique ou quelque chose)? Je voudrais que le code pour ressembler à ceci:

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

Mais comme on pouvait s'y attendre, il n'y a aucun moyen de se référer à la fonction anonyme en lui-même, ce qui est nécessaire où je mets ## RECURSE ##

Répondre

17

Oui, il est possible d'utiliser ce que l'on appelle y-combinators (ou fixed-point combinators). Ex:

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

Je ne sais pas d'articles pour F #, mais ce haskell entry pourrait également être utile. Mais: Je ne les utiliserais pas s'il y a une alternative - Ils sont assez difficiles à comprendre.

Votre code (omettez les annotations de type ici) est une construction standard et beaucoup plus expressif.

let listToString lst = 

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

    loop "" lst 
1

Notez que même si vous dites que vous utilisez la fonction qu'une seule fois, techniquement, vous faites référence par son nom deux fois, ce qui explique pourquoi il est logique de lui donner un nom.