为什么F#中的函数以这种方式实现?

Evg*_*zin 2 f#

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用作第一类值并将其传递给其他函数)

  • 另外值得注意的是F#支持定位.NET 2.0,但是`System.Func <>`和`System.Action <>`仅在.NET 3.5中引入. (8认同)