gpt4 book ai didi

types - F# 如何从其他模块推断类型和标签?

转载 作者:行者123 更新时间:2023-12-05 00:18:21 24 4
gpt4 key购买 nike

这是我用来解释我的问题的最小代码示例。以下代码被组织在两个文件中并且可以正常编译:

数据结构.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

程序.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 中,我打开命名空间并使用以模块名称为前缀的所有内容:

数据结构.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

程序.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

程序.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# 的错误还是功能?
或者换一种说法,虽然建议对标签及其类型使用相同的名称,但这似乎是类型推断机制的问题。那么这个建议是不好的,还是我以不好的方式使用命名空间、模块、类型和标签?

最佳答案

您的第一段和第二段代码之间的区别在于您在 Program.fs 中打开模块的方式。 :

  • 在您的第一个代码中,通过编写 open MyMod ,你打开模块
  • 在你的第二个版本中,写 open DataStruct ,您只打开命名空间,但还没有打开模块。如果您将其更改为 open DataStruct.MyMod ,您将获得与第一个版本完全相同的行为。

  • 我对发生的事情的粗略解释:
  • 打开模块后,F# 会看到两个 XXX float ,并且能够根据使用来消除歧义。
  • 当您使用模块名称限定时,您将限制 XXX成为最新类型XXXMyMod 中定义.第一个XXX是你的记录,第二个是从 Choice 派生的类也称为 XXX .例如,以 ILSpy 之类的方式查看您的程序集。

  • 更新:第二段不正确。当使用模块名称进行限定时,F# 编译器错误地限制了 XXX成为 DU 类型,隐藏记录类型。有关详细信息,请参阅我的第二个答案。

    关于types - F# 如何从其他模块推断类型和标签?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37968637/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com