gpt4 book ai didi

f# - 为什么 F# 编译器更喜欢生成 FSharpFunc 类型的封闭实现?

转载 作者:行者123 更新时间:2023-12-01 01:04:15 25 4
gpt4 key购买 nike

对于这段代码:

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<...>> .

最佳答案

正如 Fyodor 所指出的,不是函数创建让编译器生成隐藏类。隐藏类用于实现偏应用。

在 F# 中,部分应用程序和 lambda 被实现为编译器生成的扩展抽象类的类。 C# lambda 依赖于委托(delegate)。 IIRC Java 和 Scala 使用与 F# 类似的技术,因为 JVM 没有委托(delegate)。

我怀疑 F# 编译器为每个部分应用程序生成一个类,因为它比收集所有部分应用程序并合并相同的应用程序更简单。

它还有助于 F# 程序的可调试性,因为名称暗示了部分应用程序的完成位置:main@31-1 => 在第 31 行的 main 函数中。这个名称如果包含在日志中或性能运行可以帮助识别导致问题的部分应用程序。

如 Pavel 的评论所述,这是以增加 F# 程序集文件的大小为代价的。

关于f# - 为什么 F# 编译器更喜欢生成 FSharpFunc 类型的封闭实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51117156/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com