2

由于支持柯里化,F# 函数与普通 CLR 方法有很大不同。例如函数

let inc a = a + 1

会有类型Microsoft.FSharp.Core.FSharpFunc<int,int>。它会产生 C# 互操作性问题。必须专门设计函数以便从 C# 中轻松调用。

这种设计背后的基本原理是什么?我相信原因是咖喱支持。但是柯里化可以使用闭包来实现。例如这段代码:

let add a b = a + b
let inc = add 1

可以很容易地被编译器转换成这个:

let add a b = a + b
let inc = fun x -> add 1 + x

在这种情况下, add 和 inc 都可以是普通System.Func对象。我相信这个设计决定背后有一些有趣的原因。

4

3 回答 3

10

据我记得,在 F# 中为函数提供单独类型的动机是性能(在早期版本FSharpFunc<...>中实际上称为FastFunc<...>)。我不完全确定最近的事态发展(我确信 F# 团队做了一些测试来确定代理是否可以在 Visual Studio 2010 中工作),但我是这样理解这个问题的:

如果您有一个函数add : int -> int -> int,那么该函数可以表示为一个委托Func<int, Func<int, int>>(使用柯里化表示)。问题是你经常会想用两个参数来调用它,比如add 1 2.

使用嵌套Func类型的表示,这将编译为add.Invoke(1).Invoke(2).

但是,在编译类似add的函数时,F# 编译器实际上创建了一个新类,例如,AddClass继承FSharpFunc<int, FSharpFunc<int, int>> 添加了一个带有两个参数的额外Invoke重载。这意味着,在大多数情况下,add 1 2可以只编译为一个 call add.Invoke(1, 2)

这种设计使 F# 代码更快。它稍微使互操作性复杂化,但不会太多。编写一个接受委托的 F# 成员或函数相当容易:

let foo (inc : Func<int, int>) = inc.Invoke(41)

(您只需要添加类型注释然后调用f.Invoke- 但您也可以将f.Inokve其用作一等值并将其传递给其他函数)

于 2013-02-08T13:51:25.720 回答
1

我的猜测是 F# 表示支持大步语义,System.Func但不支持。

于 2013-02-10T18:02:15.670 回答
1

与 C# 互操作的最佳方法是将所有内容包装在类/成员中。C# 永远不必查看成员的内部工作。

于 2013-02-17T15:40:08.833 回答