Для этого кода:
module Module =
let func x y z = 0
[<EntryPoint>]
let main args =
func 1
func 1 1
0
Выход декомпиляции:
[CompilationMapping(SourceConstructFlags.Module)]
public static class Main
{
[CompilationMapping(SourceConstructFlags.Module)]
public static class Module
{
[Serializable]
internal sealed class main@30 : OptimizedClosures.FSharpFunc<object, object, int>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public int x;
[CompilerGenerated]
[DebuggerNonUserCode]
internal main@30(int x)
{
this.x = x;
}
public override int Invoke(object y, object z)
{
return func(x, y, z);
}
}
[Serializable]
internal sealed class main@31-1 : FSharpFunc<object, int>
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public int x;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public int y;
[CompilerGenerated]
[DebuggerNonUserCode]
internal main@31-1(int x, int y)
{
this.x = x;
this.y = y;
}
public override int Invoke(object z)
{
return func(x, y, z);
}
}
[CompilationArgumentCounts(new int[]
{
1,
1,
1
})]
public static int func<a, b, c>(a x, b y, c z)
{
return 0;
}
[EntryPoint]
public static int main(string[] args)
{
int x = 1;
new main@30(x);
int x2 = 1;
int y = 1;
new main@31-1(x2, y);
return 0;
}
}
public static a Dump<a>(a arg00)
{
return arg00.Dump();
}
}
Генерирует конкретный тип, то есть общие параметры предоставляются при определении типа. Почему это не делается на этапе строительства? Я также заметил, что типы генерируются в модуле, где происходит вызов, а не там, где определено func
.
Имея let func x y z = ...
, нам нужны реализации типов, чтобы охватить все возможности:
FSharpFunc<T1,FSharpFunc<T2,T3,TReturn>>
FSharpFunc<T1,T2,FSharpFunc<T3,TReturn>>
FSharpFunc<T1,FSharpFunc<T2,FsharpFunc<T3,TReturn>>>
Компилятор может генерировать все возможные комбинации в том же месте, где определена функция, закрываясь только для параметров с зависимыми типами.
Можно утверждать, что для списка из 7 аргументов набор типов будет довольно большим, но такие типы, как FSharpFunc<T1,T2,..,Tn, FSharpFunc<...>>
, являются простой оптимизацией. И FSharpFunc
поддерживает до шести универсальных типов, тогда компилятор должен переключиться на FSharpFun<T1,T2,T3,T4,T5,FSharp<...>>
.