使用F#的`ref`与`mutable`赋值运算符

时间:2011-10-18 08:18:19

标签: f# mutable assignment-operator ref

请考虑以下代码:

let mutable a = 0.
let b = ref 0.

a <- // works
  printfn "%A" a
  4. + 8.

b := // does not work
  printfn "%A" a
  4. + 8.

b := ( // works
  printfn "%A" a
  4. + 8. )

为什么ref赋值运算符(:=)的行为与可变赋值运算符(&lt ;-)不同?

4 个答案:

答案 0 :(得分:2)

我只能给出部分答案。

:=是根据FSharp.Core \ prim-types.fs中的<-定义的:

let (:=) x y = x.contents <- y

在你的例子中

b := // does not work
  printfn "%A" a
  4. + 8.

printfn "%A" a似乎被解释为y,无法将其分配给int ref单元格(错误类型)。通过将整个表达式分组为( ... )y现在还包含4. + 8.。也许两个运算符的行为不同,因为<-似乎是一个内在的运算符(即语言的一部分,而不是库)。

答案 1 :(得分:1)

:=是一个函数(try(= =);;在FSI中),其类型为:'a ref -> 'a -> unit

所以

b := // does not work
  printfn "%A" a
  4. + 8.
由于中缀调用解析规则,

正在被解析:

(:=) b (printfn "%A" a)
4. + 8.

与(= =)函数类型相同无效。 其他例子:

let c = 10 + 
            11 
            12

c将是12在这里

答案 2 :(得分:1)

以其他答案为基础......

分配中允许使用更复杂的表达式,只要最终表达式是多个允许的表单之一即可。请参阅规范的section 6.4.9。这允许复杂的分配,例如:

let x =
  let rec gcd a = function
    | 0 -> a
    | b -> gcd b (a % b)
  gcd 10 25

编译器将gcd移动到私有成员,但将其嵌套在赋值中允许更严格的作用域。另一方面,函数参数受到更多限制。它们不会创建一个新的范围(我知道)并且您无法定义函数,例如,作为表达式的一部分。

答案 3 :(得分:0)

看起来像是缩进敏感的解析器中的差异,而不是与这些运算符有关的任何内容。