F#函数与普通CLR方法有很大不同,因为支持currying.例如功能
let inc a = a + 1
Run Code Online (Sandbox Code Playgroud)
会有类型Microsoft.FSharp.Core.FSharpFunc<int,int>.它会产生C#互操作性问题.必须专门设计函数才能从C#轻松调用.
这个设计背后的理由是什么?我相信原因在于支持.但是可以使用闭包来实现currying.例如这段代码:
let add a b = a + b
let inc = add 1
Run Code Online (Sandbox Code Playgroud)
可以通过编译器轻松转换为:
let add a b = a + b
let inc = fun x -> add 1 + x
Run Code Online (Sandbox Code Playgroud)
在这种情况下,add和inc都可以是普通System.Func对象.我相信这个设计决定背后有一些有趣的原因.
Tom*_*cek 10
据我所知,在F#中为函数设置单独类型的动机是性能(在早期版本FSharpFunc<...>中实际上是调用的FastFunc<...>).我不完全确定最近的发展(我确信F#团队做了一些测试,以确定代理是否可以在Visual Studio 2010中工作),但这是我如何理解这个问题:
如果你有一个函数,add : int -> int -> int那么函数可以表示为委托Func<int, Func<int, int>>(使用curried表示).问题是你常常想用两个参数来调用它add 1 2.
使用具有嵌套Func类型的表示,这将编译为add.Invoke(1).Invoke(2).
然而,编译之类的函数时add,F#编译器实际创建一个新的类,说,AddClass它继承了来自FSharpFunc<int, FSharpFunc<int, int>> 和增加了一个额外Invoke的过载有两个参数.这意味着,在大多数情况下,add 1 2可以编译为只有一个调用add.Invoke(1, 2).
这种设计使F#代码更快.它略微复杂化了互操作性,但并不太多.编写一个带代理的F#成员或函数相当容易:
let foo (inc : Func<int, int>) = inc.Invoke(41)
Run Code Online (Sandbox Code Playgroud)
(您只需要添加类型注释然后调用f.Invoke- 但您也可以将其f.Inokve用作第一类值并将其传递给其他函数)