F# 编译器如何知道正在调用 C# 方法以及参数需要语法元组?
How does the F# compiler know that a C# method is being called and that a syntactic tuple is needed for the parameters?
参考 F# - On the parameters passed to C# methods - are they tuples or what?,当从 F# 调用 C# 方法时,参数以句法元组的形式提供。
我的理解是 C# 方法必须以这种方式调用。所以以那个问题为例,
MyClsas.Add(4, 5) |> printfn "%d"
工作正常,而
MyClsas.Add 4 5 |> printfn "%d"
会报错
This value is not a function and cannot be applied
This expression was expected to have type
int * int
but here has type
int
因此我的问题是,F# 如何知道调用的是 C# 方法并且需要语法元组?
这是因为对非 F# 库的方法调用无法柯里化;事实上,来自非 F# 库的方法的行为就好像它们接受一个参数元组一样。这就是为什么您必须调用 BCL 方法来传递分组在元组中的参数。
正如我所说,柯里化注释发生在编译 F# 代码时。这意味着编译器已根据需要确保每个函数只有一个参数。所以你可以一个一个地传递一个参数,这是一个部分应用程序。从@FuleSnabel 展示的反编译代码中我们可以看到属性Core.CompilationArgumentCountsAttribute
。在 msdn (https://msdn.microsoft.com/fr-fr/library/ee353833.aspx) 上您可以阅读以下内容:
Used internally by the compiler to indicate that a functions or member accepts a partial application of some of its arguments and returns a residual function.
我的 F# 扩展程序集元数据以支持功能概念。考虑一下:
module MyModule =
let curried x y z = x*y + z
let tupled (x,y,z) = x*y + z
MyModule 反编译:
[CompilationArgumentCounts(new int[]
{
1,
1,
1
})]
public static int curried(int x, int y, int z)
{
return x * y + z;
}
public static int tupled(int x, int y, int z)
{
return x * y + z;
}
因此 F# 似乎以属性的形式添加了额外的元数据,以帮助 F# 编译器实现 curried
与 tupled
的不同。但是用 CompiliationArgumentCounts 扩展你的 C# 方法是行不通的(我试过了)。似乎 F# 以名为 FSharpSignatureData.Curry
和 FSharpOptimizationData.Curry
.
的两个程序集资源的形式添加了更多元数据
C# 不知道此元数据,因此 curried
和 tupled
的签名在 C# 中是相同的。
如果你是好奇的人,请给个小费;下载一个很好的 .NET 反编译器(有很多)。通过反编译为 IL 或 C#,您通常可以了解很多关于语言功能的实际实现方式以及它们带来的隐藏成本。
参考 F# - On the parameters passed to C# methods - are they tuples or what?,当从 F# 调用 C# 方法时,参数以句法元组的形式提供。
我的理解是 C# 方法必须以这种方式调用。所以以那个问题为例,
MyClsas.Add(4, 5) |> printfn "%d"
工作正常,而
MyClsas.Add 4 5 |> printfn "%d"
会报错
This value is not a function and cannot be applied
This expression was expected to have type
int * int
but here has type
int
因此我的问题是,F# 如何知道调用的是 C# 方法并且需要语法元组?
这是因为对非 F# 库的方法调用无法柯里化;事实上,来自非 F# 库的方法的行为就好像它们接受一个参数元组一样。这就是为什么您必须调用 BCL 方法来传递分组在元组中的参数。
正如我所说,柯里化注释发生在编译 F# 代码时。这意味着编译器已根据需要确保每个函数只有一个参数。所以你可以一个一个地传递一个参数,这是一个部分应用程序。从@FuleSnabel 展示的反编译代码中我们可以看到属性Core.CompilationArgumentCountsAttribute
。在 msdn (https://msdn.microsoft.com/fr-fr/library/ee353833.aspx) 上您可以阅读以下内容:
Used internally by the compiler to indicate that a functions or member accepts a partial application of some of its arguments and returns a residual function.
我的 F# 扩展程序集元数据以支持功能概念。考虑一下:
module MyModule =
let curried x y z = x*y + z
let tupled (x,y,z) = x*y + z
MyModule 反编译:
[CompilationArgumentCounts(new int[]
{
1,
1,
1
})]
public static int curried(int x, int y, int z)
{
return x * y + z;
}
public static int tupled(int x, int y, int z)
{
return x * y + z;
}
因此 F# 似乎以属性的形式添加了额外的元数据,以帮助 F# 编译器实现 curried
与 tupled
的不同。但是用 CompiliationArgumentCounts 扩展你的 C# 方法是行不通的(我试过了)。似乎 F# 以名为 FSharpSignatureData.Curry
和 FSharpOptimizationData.Curry
.
C# 不知道此元数据,因此 curried
和 tupled
的签名在 C# 中是相同的。
如果你是好奇的人,请给个小费;下载一个很好的 .NET 反编译器(有很多)。通过反编译为 IL 或 C#,您通常可以了解很多关于语言功能的实际实现方式以及它们带来的隐藏成本。