使用F#lambda作为期望System.Func

时间:2015-07-29 22:59:13

标签: f#

假设我有一些像

这样的库代码
open System

module Foo =
    let Invoke1 (action : Func<string>) = ()
    let Invoke2 (action : Func<int, string>) = ()
    let Invoke3 (key : int, add : Func<int, string>, update: Func<int, string, string>) = ()       
    let Invoke4 (key : int) (add : Func<int, string>) (update: Func<int, string, string>) = ()

type Bar =
    static member Invoke1 (action : Func<string>) = ()
    static member Invoke2 (action : Func<int, string>) = ()
    static member Invoke3 (key : int, add : Func<int, string>, update: Func<int, string, string>) = ()
    static member Invoke4 (key : int) (add : Func<int, string>) (update: Func<int, string, string>) = ()

现在,当调用这些方法时,实际上存在行为差异

首先,以下三行不编译

Foo.Invoke1(fun () -> "") 
Foo.Invoke2(fun a -> "") 
Foo.Invoke3(5, (fun k -> ""), (fun k v -> v))

它们都有相同的编译错误

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

但是,以下三行编译得很好

Bar.Invoke1(fun () -> "") 
Bar.Invoke2(fun a -> "")
Bar.Invoke3(5, (fun k -> ""), (fun k v -> v)) 

因此,当某个类型的静态成员接受System.Func时,可以隐式转换和接受相应的F#lambda。但是为了让模块绑定,它不起作用?

我还使用ILSpy来查看生成的IL。对于Foo.Invoke1和Bar.Invoke1,它们在IL中具有与

相同的签名
.method public static 
  string Invoke1 (
    class [mscorlib]System.Func`1<string> action
  ) cil managed 

因此IL中的方法本身没有区别。对于那种类型,我看到了

.class public auto ansi abstract sealed Library.Foo
.class public auto ansi serializable Library.Bar

所以这会以某种方式造成差异?无论如何,如何解释模块和类型之间的行为差​​异?

然后我还发现以下内容无法编译

Bar.Invoke4 (5) (fun k -> "") (fun k v -> v)

出现错误

error FS0001: This expression was expected to have type    int    but here has type    unit

Bar.Invoke3和Bar.Invoke4之间的区别在于前者使用元组形式而后者使用currying形式。但是,不知何故,后者不编译。万一你好奇

Foo.Invoke4 (5) (fun k -> "") (fun k v -> v)

也不编译,只是错误不同,它与所有其他“Foo”错误相同:

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

有关为什么Bar.Invoke3有效,但Bar.Invoke4没有的想法

当从F#lambda到System.Func的隐式转换发生并且不可能发生时,真的很混乱。对上述行为有什么解释?

我发现了一些早先的相关问题,例如

但仍无法找到行为的明确解释。

有什么想法吗?

注意:我用F#4.0尝试了上面的代码

某些上下文:当我试图探索是否可以编写F#库时,我发现了这样的行为,其中一些方法将functor作为参数。我能否以可以从F#/ C#代码中使用它的方式编写它。我记得我可以使用带有System.Func作为参数的.Net方法的F#lambda(例如ConcurrentDictonary的AddOrUpdate)。所以我想如果我的函数使用System.Func,它可以同时服务。 这是一个好/坏的假设

1 个答案:

答案 0 :(得分:4)

在F#中,类型导向的转换仅适用于类型成员的调用(F#spec 8.13.7)