是什么让FSharpFunc <>比Func <>更快?

Joh*_*aze 22 f# delegates

我很好奇为FSharpFunc <>所做的性能增强.事实上它不包含多个委托,因此在触发函数调用时不需要遍历所有引用吗?还要别的吗 ?

Tom*_*cek 25

我认为使用FSharpFunc<>而不是Func<>或任何其他委托的主要动机是你不能创建一个从委托类型继承的类(起初,这听起来很合理,但在.NET中,委托实际上只是一些特殊的类,所以原则上可以允许这样做).为什么需要这个?

如果你在F#中编写一个函数,那么(在一个相对较少但非常重要的情况下)以curry形式处理.例如int -> int -> int,实际上是一个函数类型int -> (int -> int)(currying意味着你只使用单个参数的函数编写一个函数 - 如果你用第一个参数调用它,你将得到一个函数作为结果,你可以用第二个函数调用返回的函数参数).

如果F#使用了委托,那么类型就是这样的Func<int, Func<int, int>>.正如Brian所说,调用f x y将被转换为两个调用:f(x)(y).然而,这种调用是最常见的(仅指定一个参数称为部分函数应用程序).因此,当F#编译这样的函数时,它会创建一个带有优化的invoke方法的继承类,因此可以调用它f.Invoke(x, y):

class @some_F#_name@ : Func<int, Func<int, int>> {
   public int Invoke(int arg1, int arg2) { /* optimized call */ }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,不可能通过继承标准来创建这样的类Func(因为它是一个委托),所以F#必须声明它自己的类型,它可以用作基类......


Bri*_*ian 12

(我认为他们现在被称为FSharpFunc而不是FastFunc.)

它表示为具有单个抽象方法(Invoke)的类型,我认为这避免了使用真正的委托获得的一些开销.对于多个curried参数,它使您能够"一次"调用所有参数,而不是逐个f x y调用(例如,因此可以在CLR上调用f(x,y)而不是f(x)(y).

还有别的事吗?我现在不记得了.您可以在CTP版本附带的源代码发行版中查看FSharp.Core中prim-types.fs中的源代码.

  • 出于好奇,在编写普通的 let 绑定时是否隐式使用了 FSharpFunc? (2认同)
  • 任何时候您需要表示类型为 X-&gt;Y 的 _object_,我认为它将被表示为 FSharpFunc 的一个实例。当您定义 let-bound 函数时,这些函数可以表示为 CLR 的普通方法,但是如果您将这些函数用作值(例如将其作为参数传递给 List.map 或诸如此类),那么它将通过FSharpFunc。 (2认同)