Почему F# currying "выравнивает" тип функции?
Следующая функция:
let twoInputs x y =
let sum = x + y
let product a = sum * a
product
Имеет вид:
val twoInputs : x:int -> y:int -> (int -> int)
Это вполне разумно, я понимаю, почему это происходит. Но почему эта функция:
let oneInput = twoInputs 1
Относится к типу val oneInput : (int -> int -> int)?
Разве это не должно быть int -> (int -> int)?
int -> int -> (int -> int) и int -> int -> int -> int. Если да, то почему бы просто не указать последний тип функции для twoInputs?1 ответ:
Скобки означают " значение типа FsharpFunc<_>", а отсутствие скобок означает"метод true CLR". В вашем примере
На самом деле вы можете достичь того же эффекта (т. е. превратить истинный метод в ценность) даже без карринга, очень просто:twoInputкомпилируется в метод true CLR, но возвращает значение типаFSharpFunc<_>, следовательно, его тип. Но вашoneInputкомпилируется в поле класса типаFSharpFunc<_>, и, следовательно, его тип.> let twoInputs x y = > let sum = x + y > let product a = sum * a > product > let twoInputsAgain = twoInputs val twoInputs : x:int -> y:int -> (int -> int) val twoInputsAgain : (int -> int -> int -> int)Это происходит потому, что CLR не поддерживает понятие "назначение метода", поэтому F# должен скомпилировать это, объявив
twoInputsAgainкак поле типаFSharpFunc<_>и затем назначив ему экземпляр класса, который наследует отFSharpFunc<_>и вызываетtwoInputs, КогдаInvoked.Если вы декомпилируете его на C# (я использую ILSpy), это то, что вы видите:
В заключение я хочу отметить, что это разделение не имеет большого значения на практике, если только вы не практикуете действительно темную магию, поэтому вам не следует беспокоиться об этом.static $Program() { $Program.twoInputsAgain@11 = new Program.twoInputsAgain@11(); } internal class twoInputsAgain@11 : OptimizedClosures.FSharpFunc<int, int, FSharpFunc<int, int>> { public override FSharpFunc<int, int> Invoke(int x, int y) { return Program.twoInputs(x, y); } }