Подтвердить что ты не робот

Что делает FSharpFunc <> быстрее, чем Func <>?

Мне интересны улучшения производительности, которые были сделаны для FSharpFunc < > . Это факт, что он не содержит нескольких делегатов, поэтому нет необходимости перебирать все ссылки при запуске вызова функции? Что-нибудь еще?

4b9b3361

Ответ 1

Я думаю, что основной мотивацией использования FSharpFunc<>, а не Func<> или любого другого делегата является то, что вы не можете создать класс, который наследует от типа делегата (сначала это звучит разумно, но в .NET, делегат на самом деле просто какой-то особый класс, поэтому в принципе это возможно). Почему это необходимо?

Если вы напишете функцию в F #, то она (в относительно немногих, но довольно важных случаях) обрабатывается в карри. Например, int -> int -> int фактически является типом функции int -> (int -> int) (currying означает, что вы пишете функцию, используя только функции одного параметра - если вы вызываете ее с первым аргументом, вы получите функцию в результате и вы можете вызвать возвращаемая функция со вторым аргументом).

Если F # использовал делегатов, тип был бы чем-то вроде Func<int, Func<int, int>>. Как отметил Брайан, обращение f x y будет переведено на два вызова: f(x)(y). Однако этот вид вызова является наиболее распространенным (указание только одного аргумента называется приложением частичной функции). Таким образом, когда F # компилирует такую ​​функцию, она создает унаследованный класс с оптимизированным методом invoke, так что его можно вызвать как f.Invoke(x, y):

class @some_F#[email protected] : Func<int, Func<int, int>> {
   public int Invoke(int arg1, int arg2) { /* optimized call */ }
}

К сожалению, создать такой класс невозможно, наследуя от стандартного Func (потому что он является делегатом), поэтому F # должен объявить свой собственный тип, который может использоваться как базовый класс...

Ответ 2

(Думаю, теперь они называются FSharpFunc, а не FastFunc.)

Он представлен как тип с единственным абстрактным методом (Invoke), который, я думаю, позволяет избежать некоторых накладных расходов, которые вы получаете с истинными делегатами. И для нескольких параметров в карри, это позволяет вам вызывать со всеми параметрами "сразу", а не по одному (например, чтобы f x y можно было вызывать в CLR как f(x,y), а не f(x)(y).

Есть ли что-нибудь еще? Я не помню прямо сейчас. Вы можете проверить исходный код в prim-types.fs в FSharp.Core в исходном дистрибутиве, который поставляется с релизом CTP.