【问题标题】:Error FS0037 sometimes, very confusing有时会出现错误FS0037,非常混乱
【发布时间】:2016-07-29 06:45:45
【问题描述】:

如果我编写以下 F# 代码,编译器会发出错误。

let a = 123
let a = 123

产生的错误是:

错误 FS0037:值“a”的重复定义

如果我在这样的函数中编写相同的代码:

let fctn = 
    let a =123
    let a =123
    a

它不会产生任何错误。

我不明白其中的区别。谁能解释一下?

编辑:我在模块级别编写的第一个代码。

【问题讨论】:

  • 不清楚你在问什么。提供mcve
  • 将这些剪切并粘贴到 fsi 中会产生基本上相同的错误。
  • 来自MSDN Functions (F#)At any level of scope other than module scope, it is not an error to reuse a value or function name. If you reuse a name, the name declared later shadows the name declared earlier. However, at the top level scope in a module, names must be unique.

标签: f# functional-programming shadowing


【解决方案1】:

我同意这令人困惑。问题是let 在用作局部变量(在函数内)和用作全局定义(在模块内)时的行为不同。

全局定义(在模块中)被编译为静态类的静态成员,因此名称只能使用一次。这意味着顶级使用:

let a = 10
let a = 11

... 是一个错误,因为 F# 必须生成两个同名的静态成员。

局部定义(在函数或其他嵌套范围内)被编译为 IL 并且变量名基本上消失了(IL 使用堆栈代替)。在这种情况下,F# 允许变量隐藏,您可以隐藏现有名称的变量。这可以在函数内部,甚至只是一个do 块:

do
  let a = 10
  let a = 11
  ()

这有点令人困惑,因为变量阴影仅在局部范围内有效,而在顶层无效。但是,当您知道事物是如何编译时,这才有意义..

【讨论】:

  • 是的!对您的回答非常满意。
  • 这不仅令人困惑,而且在 OCaml 中也不是这样的
【解决方案2】:

关于范围和阴影

正如 CaringDev 提到的(但未解释),当您使范围更明显时,您可能会看到阴影是什么(使用 let ... in ... 构造 #light let 您可以缩短位 - 但即使没有#light off,您仍然可以使用它)

试试这个:

> let a = 233 in let a = 555 in a;;
val it : int = 555

如您所见,表达式计算为ashadowed 值 - 但原始值并没有丢失:

> let a = 233 in (let a = 555 in a), a;;
val it : int * int = (555, 233)

它只是不在内部let ... in ...的范围内

顺便说一句:您可以将示例重写为:

let fctn = 
    let a = 123 in
    (let a =123 in a)

(我添加括号只是为了让这一点更明显)


模块级别的另一个确实为模块的范围定义了一个值,并且不是真正的表达式而是定义

【讨论】:

  • 是的,在我的手机上写...计划稍后添加说明。谢谢。
【解决方案3】:

第一个定义了两个同名的公共值。

第二个隐藏(阴影)一个值。

第一个你会有外部可见的状态变化(a 表现得像可变),而第二个你不能(你有两个as 在不同的范围内)。

如果您使用#light off ML 语法编写语句,它会立即变得显而易见。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    • 2018-11-30
    • 1970-01-01
    • 2016-11-19
    • 1970-01-01
    • 2011-09-09
    相关资源
    最近更新 更多