在F#中使用Lambda表达式创建委托

7

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)

当代码无法编译时:

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

我没有查看规范以确认,但我猜想从“lambda”到“命名委托类型”的隐式转换只发生在“成员调用”中。

您始终可以明确进行转换:

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

(错误的诊断信息相当差; 我会报告Bug。)

编辑:

对于专业人士...

是的,规范说:

8.13.6 在成员调用中进行类型引导转换 正如方法应用解析(参见 §14.4)中所述,在方法调用中应用两个类型引导转换。

如果一个形式参数是委托类型DelegateType,而实际参数在语法上是一个函数值(fun ...),则该参数被解释为如果它已经被写成new DelegateType(fun ...)。

lambda表达式仅在 "成员调用" 时自动转换为委托类型。 在柯里化成员的情况下,传递的第一个参数是成员调用,但然后将返回函数值以应用第二个参数,并且函数调用不具有此隐式转换规则。


谢谢。什么是“成员调用”,为什么使用元组参数会有所不同?成员是否应始终采用元组参数? - Matthew H
3
“Members”是您使用“member”关键字定义的内容,例如某种类型上的静态或实例方法。这些与“functions”形成对比,后者是通过let f x = ...fun定义的,并且相对非常严格(例如,您不能重载函数,但可以重载成员)。成员应该始终采用元组参数;与函数不同,成员更像.NET实体,而函数更具F#特定性。 - Brian
3
“tupled arguments” 的作用在于当以元组形式传递参数时,所有参数一次性传递给成员函数,因此第二个参数就是成员函数的一个参数。而柯里化函数的情况下,第一个参数是成员函数的参数,这会导致生成一个新的(非成员)函数值,该函数再接收第二个参数。 - Brian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接