假设我有一些像
这样的库代码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。函数,相应的f# lambda可以隐式转换和接受。但是对于模块的let绑定,它不起作用?
我还使用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是前者使用元组形式,后者使用curry形式。然而,不知何故,后者不能编译。如果你很好奇
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
知道为什么吗?Invoke3工作,但Bar。Invoke4没有?
当从f# lambda隐式转换到System。什么时候会发生,什么时候不会发生。对上述行为的解释是什么?
我发现了一些早前的相关问题,比如
- 传递f#函数给IEnumerable。Where vs IEnumerable。所有的
- lambda表达式到Func的转换
但仍然找不到一个明确的解释。
任何想法?
注意:我用f# 4.0试过上面的代码
一些上下文:当我试图探索是否可以编写一个f#库,其中一些方法以函子作为参数时,我发现了这样的行为。我能不能把它写成一种可以在f#/c#代码中使用的方式?我记得我可以在。net方法中使用f# lambda。函数作为参数(例如concurrentdictionary的AddOrUpdate)。所以我想如果我的函数使用System。Func,它可以服务于两者。这是一个好/坏的假设?
在f#中,类型定向转换只应用于类型成员的调用(f# spec 8.13.7)