Почему 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
, КогдаInvoke
d.Если вы декомпилируете его на 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); } }