在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
。
虽然问题实际上是使用tuple参数调用编译的,但在调用Estimate
时会出现运行时错误。
“System.TypeInitializationException”类型的未处理异常 发生在LibraryTest.dll
中附加信息:类型初始化程序 'GenericZeroDynamicImplTable`1'引发了异常。
答案 0 :(得分:2)
编译一个用于F#的F#DLL,使用独立开关不是一个好主意。
为什么呢?因为所有F#元数据都丢失了,因为整个F#类型都包含在DLL中,因此这些类型与调用DLL或fsi的F#应用程序的类型具有不同的标识。
调用者程序集使用Fsharp.Core.dll中的类型,这些类型现在与独立编译的DLL中使用的类型不同。
这就是为什么你会看到tupled参数,从C#中可以看出它根本不理解F#元数据。
使用静态约束的通用内联函数也会中断,因为它们需要在调用站点内联元数据。
将调用者程序集编译为独立会使事情变得更糟,然后您将拥有3组具有不同身份的Fsharp类型。
我认为独立开关在“最终用户”应用程序中使用时很好。