Я думаю, что основной причиной использования FSharpFunc<>
вместо Func<>
или любого другого делегата является то, что вы не можете создать класс, который наследовал бы от типа делегата (сначала это звучит разумно, но в .NET, фактически делегат - это просто какой-то особый класс, поэтому в принципе это возможно. Зачем это нужно?
Если вы пишете функцию на F #, то она (в относительно небольшом, но весьма важном случае) обрабатывается в форме карри. Например, int -> int -> int
на самом деле является типом функции int -> (int -> int)
(каррирование означает, что вы пишете функцию, используя только функции с одним параметром - если вы вызываете ее с первым аргументом, вы получите функцию в результате и сможете вызывать возвращаемая функция со вторым аргументом).
Если бы F # использовал делегатов, тип был бы что-то вроде Func<int, Func<int, int>>
. Как упоминал Брайан, вызов 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 */ }
}
К сожалению, невозможно создать такой класс путем наследования от стандартного Func
(потому что это делегат), поэтому F # должен объявить свой собственный тип, который можно использовать в качестве базового класса ...