如何在 F# Program.fs 中隐藏记录?

How to shadow a record in F# Program.fs?

我正在阅读 F# 书籍 Get Programming with F# 并了解了有关阴影的部分。他们提供的最简单示例似乎是不可能的,所以我想知道是否为 F# 6 阴影删除或更改了此语法?我一直没能找到任何说明或如何做这本书提供的影子记录。

type Address =
    { Street: string
      Town: string
      City: string }

let home = { Street = "123 Main Street"; Town = "The Town"; City = "The City" }
let home = { home with City = "Second City" }
let home = { home with City = "Third City" }

尝试构建时收到错误消息:Duplicate definition of value 'home'


编辑

所以在搜索了为什么这不起作用的答案但没有成功之后,我尝试将上面的内容放入一个函数中,如下所示:

let testFunction = 
    let home = { Street = "123 Main Street"; Town = "The Town"; City = "The City" }
    let home = { home with City = "Second City" }
    let home = { home with City = "Third City" }
    0

而且效果很好。所以我现在的问题是为什么阴影在函数内起作用而不是在函数外?是否与函数范围内未发生的模块级别范围界定发生冲突?

Why shadowing is limited to function body?

可能有一些技术原因。但核心原因是IMO:

命名很难。遮蔽可以减轻疼痛,但可能会造成混淆。

F# 还支持“勾选命名”(home') 以具有相似但不同的名称。这是一种更安全的阴影。

为了向现有答案添加更多细节,有四种不同的情况。

局部定义。如果你在一个函数体内,你可以使用阴影,这在多步计算时非常有用:

let adjust index = 
  let index = max 0 index
  let index = min 100 index
  index

class. 中的局部定义 同样允许您隐藏 class:

中的局部定义
type A() = 
  let foo = 1
  let foo = 2
  member x.Foo = foo

脚本文件的顶层。如果您在脚本文件 (something.fsx) 的顶层,则允许您隐藏。脚本文件的想法是它们将是 运行 手动的,因此拥有多个不同的版本很有用 - 你只需 运行 你想要的手动版本:

let test = calculation1 ()
let test = caluclation2 ()

模块(源文件)中的顶层。阴影的唯一情况是当你在模块(或隐式成为模块的 .fs 文件)。在一个模块中,定义是 public 并且它们被编译为 class 的静态成员,因此也存在技术限制(不能有多个同名的 class 成员)。

module Constants = 
  let answer = 1
  let answer = 42 // error FS0037: Duplicate definition of value