这是我用来解释我的问题的最小代码示例。以下代码组织在两个文件中并编译好:
DataStruct.fs
module MyMod
type XXX = {
a: int
}
with
static member GetNew =
{
a = -1
}
type YYY = {
a: float
}
with
static member GetNew =
{
a = -1.0
}
type Choice =
| XXX of XXX
| YYY of YYY
Program.fs
open MyMod
let generator =
let res = XXX.GetNew
Choice.XXX res
let myVal : XXX =
match generator with
| XXX x -> x
| _ -> printfn "expected XXX, got sth else!"; XXX.GetNew
有趣的是,我有一个Choice类型,它有两个标签的名称与它们标记的类型相同。据我所知,这是F#中的一个常见惯例。
现在我更改DataStruct,以便将其放在命名空间中,并使MyMod成为该命名空间中的一个模块。因此,在Program.fs中,我打开命名空间并使用前缀为模块名称的所有内容:
DataStruct.fs
namespace DataStruct
module MyMod =
type XXX = {
a: int
}
with
static member GetNew =
{
a = -1
}
type YYY = {
a: float
}
with
static member GetNew =
{
a = -1.0
}
type Choice =
| XXX of XXX
| YYY of YYY
Program.fs
open DataStruct
let generator =
let res = MyMod.XXX.GetNew
MyMod.Choice.XXX res
let myVal : MyMod.XXX =
match generator with
| MyMod.XXX x -> x
| _ -> printfn "expected XXX, got sth else!"; MyMod.XXX.GetNew
现在Program.fs包含两个错误。在我尝试调用GetNew的两行中,它说:“字段,构造函数或成员'GetNew'未定义” 这是因为MyMod.XXX被推断为MyMod.Choice类型的并集案例。
现在,在不更改我的代码的任何结构的情况下,我只是将Choice标记重命名为与它们所代表的类型不同,并且一切正常。
DataStruct.fs如上所述,但带有
type Choice =
| TX of XXX
| TY of YYY
Program.fs
open DataStruct
let generator =
let res = MyMod.XXX.GetNew
MyMod.Choice.TX res
let myVal : MyMod.XXX =
match generator with
| MyMod.TX x -> x
| _ -> printfn "expected XXX, got sth else!"; MyMod.XXX.GetNew
现在调用GetNew是合法的,因为MyMod.XXX被正确推断为我打算使用的类型。
现在的问题是:上面描述的问题是F#的错误或特征吗? 或者换句话说,虽然建议对标签及其类型使用相同的名称,但似乎是类型推断机制的问题。那么建议是坏的还是我使用名称空间,模块,类型和标签的方式不好?
答案 0 :(得分:5)
第一段和第二段代码之间的区别在于您如何在Program.fs
中打开模块:
在第一段代码中,通过编写open MyMod
,打开模块
在您的第二个版本中,通过编写open DataStruct
,您只需打开命名空间,但尚未该模块。如果将其更改为open DataStruct.MyMod
,您将获得与第一个版本完全相同的行为。
我对正在发生的事情的粗略解释:
XXX
浮动,并且能够根据用途消除歧义。 XXX
限制为XXX
中定义的最新类型MyMod
。第一个XXX
是您的记录,第二个是从Choice
派生的类,也称为XXX
。例如,看一下像ILSpy这样的装配体。更新:第二段不正确。使用模块名称限定时,F#编译器会错误地将XXX
限制为DU类型,从而遮蔽记录类型。有关详细信息,请参阅我的第二个答案。
答案 1 :(得分:1)
此行为是编译器中的错误。该问题与编译器中的另一个错误有关,其中有区别的联合类型正在影响同一模块中的其他类型定义see this bug report。在您发布的代码中:错误的根本原因是名称解析中的here。 MyMod.XXX
被标识为引用DU类型的有效表达式。这次搜索是贪婪地完成的,codepath that searches for alternative resolutions没有被执行。
我已提交错误报告in visualfsharp和fsharp