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

Posted

技术标签:

【中文标题】F# 函数在使用独立开关编译并从另一个项目引用时更改类型【英文标题】:F# function changes type when compiled with standalone switch and referenced from another project 【发布时间】:2015-01-22 21:23:23 【问题描述】:

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

这里有什么问题?是编译器的bug吗?

编辑: 再深入一点,问题似乎与LanguagePrimitives.GenericZero 的使用有关。

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

“System.TypeInitializationException”类型的未处理异常 发生在 LibraryTest.dll 中

附加信息:类型初始化器 'GenericZeroDynamicImplTable`1' 抛出异常。

【问题讨论】:

【参考方案1】:

编译一个打算在 F# 中使用的 F# DLL,使用独立开关不是一个好主意。

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

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

这就是为什么您会看到元组参数,从根本不理解 F# 元数据的 C# 中可以看出。

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

同时将调用程序程序集编译为独立程序会使事情变得更糟,那么您将拥有 3 组具有不同身份的 Fsharp 类型。

我认为独立开关仅在“最终用户”应用程序中使用时很好。

【讨论】:

这是有道理的。谢谢。我正在调查我的问题是否仅与--standalone 开关有关(请参阅我的编辑)。我想我现在已经在不使用--standalone 的情况下产生了异常。这属于自己的问题。

以上是关于F# 函数在使用独立开关编译并从另一个项目引用时更改类型的主要内容,如果未能解决你的问题,请参考以下文章

为 websocket 提升堆栈协程,如何发布函数并从另一个线程恢复

传递信息并从另一个线程通知一个线程的最简单方法

Durandal:在一个孩子中创建功能并从另一个孩子中消费

如何从远程仓库中的 master 删除 GIT 分支并从另一个分支启动新分支?

F# 编译器需要项目引用,但方法是私有的

GitLab重命名分支并从另一个重新开始