Создание делегатов с лямбда-выражениями в F # - PullRequest
7 голосов
/ 06 мая 2010

Почему ...

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)

не компилируется, когда:

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

делает

Единственное отличие состоит в том, что во втором ApplyDelegate принимает свои параметры как кортеж.

Эта функция принимает слишком много аргументов или используется в контексте, где функция не ожидается

1 Ответ

11 голосов
/ 06 мая 2010

Я не смотрел на спецификацию для подтверждения, но я предполагаю, что неявное преобразование из "лямбды" в "именованный тип делегата" происходит только в "вызовах членов".

Вы всегда можете сделать преобразование явным:

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

(Диагностика ошибок довольно плохая; я сообщу об ошибке.)

EDIT:

За чудеса ...

Да, спецификация говорит

8.13.6 Преобразования с указанием типов при вызовах членов Как описано в Разрешение приложения метода (см. §14.4), два преобразования типа применяются при вызове метода.

Если формальный параметр имеет делегат тип DelegateType и фактический Аргумент является синтаксически функцией значение (веселье ...), то параметр интерпретируется как если бы оно было написано новый тип делегата (забавный ...).

что лямбды автоматически преобразуются в типы делегатов только при «вызовах членов». В случае каррированного члена первый передаваемый аргумент является вызовом члена, но затем он возвращает значение функции для применения второго аргумента, и вызовы функции не имеют этого неявного правила преобразования.

...