F# 函数在使用独立开关编译并从另一个项目引用时更改类型

F# function changes type when compiled with standalone switch and referenced from another project

在 F# 库的 Visual Studio 项目中,我将一个函数定义为

let inline Estimate (s : ^a seq) (f : float) (w : int) : float * float = ..

Estimate的类型是

val Estimate : s:seq<'a> -> f:float -> w:int -> float*float

从该项目中的脚本调用 Estimate 按预期工作。

现在,如果我使用 --standalone 开关编译项目并引用另一个项目的输出 DLL,Estimate 显示为

Estimate<'a,'a>(s: Collections.Generic.IEnumerabls<'a>, f: float, w:int) : float*float

即现在出于某种原因需要元组参数。 因此以下内容不起作用

let q, p = EstimationQuality.Estimate x f 1 // This value is not a function and cannot be applied

但使用元组参数调用它工作正常

let q, p = EstimationQuality.Estimate (x, f, 1) // No problem.

这是怎么回事?它是编译器中的错误吗?

编辑:
再深入一点,问题似乎与 LanguagePrimitives.GenericZero.

的使用有关

虽然问题实际上是通过元组参数调用编译的,但在调用 Estimate 时出现运行时错误。

An unhandled exception of type 'System.TypeInitializationException' occurred in LibraryTest.dll

Additional information: The type initializer for 'GenericZeroDynamicImplTable`1' threw an exception.

使用独立开关编译旨在从 F# 使用的 F# DLL 不是一个好主意。

为什么?因为所有 F# 元数据都丢失了,因为整个 F# 类型集都包含在您的 DLL 中,所以这些类型与调用您的 DLL 或 fsi 的 F# 应用程序的类型获得不同的标识。

调用方程序集使用 Fsharp.Core.dll 中的类型,现在与独立编译的 DLL 中使用的类型不同。

这就是您看到元组参数的原因,正如 C# 所见,它根本不理解 F# 元数据。

使用静态约束的通用内联函数也会中断,因为它们需要元数据在调用站点内联。

将调用程序集也编译为独立程序会使事情变得更糟,然后您将拥有 3 组具有不同标识的 Fsharp 类型。

我认为独立开关仅在 'end-user' 应用程序中使用时很好。