2010-05-06 9 views
6

Pourquoi ...délégués avec des expressions lambda dans F #

type IntDelegate = delegate of int -> unit 

type ListHelper = 
    static member ApplyDelegate (l : int list) (d : IntDelegate) = 
     l |> List.iter (fun x -> d.Invoke x) 

ListHelper.ApplyDelegate [1..10] (fun x -> printfn "%d" x) 

ne compilera pas, lorsque:

type IntDelegate = delegate of int -> unit 

type ListHelper = 
    static member ApplyDelegate (l : int list, d : IntDelegate) = 
     l |> List.iter (fun x -> d.Invoke x) 

ListHelper.ApplyDelegate ([1..10], (fun x -> printfn "%d" x)) 

fait?

La seule différence est que dans le second, ApplyDelegate prend ses paramètres sous la forme d'un tuple.

Cette fonction prend trop d'arguments, ou est utilisé dans un contexte où une fonction ne devrait

Répondre

11

Je ne l'ai pas regardé les spécifications pour confirmer, mais je devine que la conversion implicite de "lambda" à "type de délégué nommé" ne se produit que dans un "invocations de membres".

Vous pouvez toujours effectuer la conversion explicite:

ListHelper.ApplyDelegate [1..10] (IntDelegate(fun x -> printfn "%d" x)) 

(L'erreur de diagnostic est assez pauvre, je déposerai un bug.)

EDIT:

Pour les aficionados .. .

Ouais, le spec dit

8.13.6 Conversions dirigées par type lors d'invocations de membres Comme décrit dans Méthode Application Résolution (voir §14.4), deux conversions de type sont appliquées aux invocations de méthode.

Si un paramètre formel est délégué de type DelegateType, et un argument réel est syntaxiquement une valeur de fonction (fun ...), le paramètre est interprété comme si elle avait été écrite nouvelle DelegateType (fun ...).

que les lambdas soient convertis automagiquement pour ne déléguer des types qu'aux "invocations de membres". Dans le cas du membre curry, le premier argument passé est un appel de membre, mais cela retourne une valeur de fonction pour appliquer le second argument, et les invocations de fonction n'ont pas cette règle de conversion implicite.

+0

Merci. Qu'est-ce qu'une «invocation de membre» exactement et pourquoi avoir des arguments multipliés fait-il une différence? Les membres doivent-ils toujours prendre des arguments multiplicateurs? –

+3

"Membres" sont des éléments que vous définissez avec le mot-clé "member", par ex. méthodes statiques ou d'instance sur un certain type. Celles-ci contrastent avec les «fonctions» qui sont définies par 'let f x = ...' ou 'fun' et qui sont comparativement très strictes (par exemple, vous ne pouvez pas surcharger une fonction, mais vous pouvez surcharger un membre). Les membres devraient probablement toujours prendre des arguments multipliés, oui; les membres sont plus d'entités .NET-y, par rapport aux fonctions qui sont spécifiques à F #. – Brian

+3

Les 'arguments tuplés' font la différence parce que quand ils sont tuplés, tous les arguments sont passés 'à la fois' au membre, donc le second argument est un argument à un membre. Dans le cas d'arguments au curry, le premier argument est un argument au membre, et cela aboutit à une nouvelle valeur de fonction (non membre), qui prend alors le second argument. – Brian

Questions connexes