Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating Delegates With Lambda Expressions in F#

Why does...

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)

not compile, when:

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

does?

The only difference that is that in the second one, ApplyDelegate takes its parameters as a tuple.

This function takes too many arguments, or is used in a context where a function is not expected

like image 302
Matthew H Avatar asked May 06 '10 18:05

Matthew H


1 Answers

I haven't looked at the spec to confirm, but I am guessing that the implicit conversion from "lambda" to "named delegate type" only occurs in a "member invocations".

You can always make the conversion explicit:

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

(The error diagnostic is quite poor; I'll file a bug.)

EDIT:

For the wonks...

Yeah, the spec says

8.13.6 Type-directed Conversions at member invocations As described in Method Application Resolution (see §14.4), two type-directed conversions are applied at method invocations.

If a formal parameter is of delegate type DelegateType, and an actual argument is syntactically a function value (fun ...), then the parameter is interpreted as if it had been written new DelegateType(fun ...).

that lambdas get converted automagically to delegate types only at "member invocations". In the case of the curried member, the first argument passed is a member invocation, but then that returns a function value to apply the second argument, and function invocations do not have this implicit conversion rule.

like image 113
Brian Avatar answered Nov 13 '22 07:11

Brian