【问题标题】:F# throws warning in shadowing record typeF# 在阴影记录类型中引发警告
【发布时间】:2023-03-09 10:56:01
【问题描述】:

我有 2 种具有相同签名的记录类型:

type T1 = { a : int }
type T2 = { a : int }

let badFunc record = { record with a = 0 }
let goodFunc (record : T2) = { record with a = 0 }

编译器会在badFunc函数中抛出警告:

此记录表达式或模式的字段标签和预期类型不能唯一确定对应的记录。

来自F# RFC FS-1025 - Improve record type inference

解析记录类型时,编译器的当前行为是为记录类型的每个字段查找范围内具有该字段的所有类型。然后它为所有字段获取这些类型的交集,如果找到一个匹配的类型,则选择该类型。否则,会盲目选择列表中的第一个类型,从而导致错误。

所以 F# 应该知道 badFunc 类型是 T2 -> T2,为什么 F# 会忽略阴影并抛出警告?

【问题讨论】:

  • 对不起,我看不出 F sharp 应该如何知道 badFunc 中的记录类型
  • @flq 如果T2T1 之后声明,为什么不应该选择它?
  • 类型T2不影响T1,所以类型不明确。

标签: .net f# functional-programming record


【解决方案1】:

如 cmets 中所述,记录 T1 不会被记录 T2 遮蔽。我可以看到这个推理可能来自哪里,因为这就是变量阴影的工作原理:

let foo () =
  let a1 = 10
  let a1 = 20
  a1

这里,a1 的第二个声明隐藏了第一个。对于记录,您可能希望同名记录会隐藏之前的声明:

type T1 = { a : int }
type T1 = { a : int }

但是,这不起作用,您会收到一条错误消息:

错误 FS0037:类型、异常或模块“T1”的重复定义

在您的定义中,您定义了两种不同的类型T1T2,它们恰好具有相同的字段。您始终可以使用完全限定的语法来引用该字段:

let t1Func record = { record with T1.a = 0 }
let t2Func record = { record with T2.a = 0 }

当你只写a 时编译器应该怎么做?这是一个设计决策——它可以自动选择两者之一,但这通常有点令人困惑,因为它可能取决于您打开命名空间的顺序。因此,像编译器目前所做的那样,发出警告可能是更明智的方法。

【讨论】:

    猜你喜欢
    • 2014-08-14
    • 2014-03-28
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 2019-04-05
    • 2019-07-06
    • 1970-01-01
    相关资源
    最近更新 更多