Ответ 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 # должен объявить свой собственный тип, который может использоваться как базовый класс...