考虑以下代码:
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 赋值运算符 (:=) 与可变赋值运算符 (<-) 的行为不同?
考虑以下代码:
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 赋值运算符 (:=) 与可变赋值运算符 (<-) 的行为不同?
我只能给出部分答案。
:=
<-
在 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.
。也许这两个运算符的行为不同,因为<-
似乎是一个内在的运算符(即语言的一部分,而不是库)。
:=
是一个函数(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
在其他答案的基础上...
只要最终表达式是几种允许的形式之一,就可以在赋值中使用更复杂的表达式。请参阅规范的第 6.4.9 节。这允许进行复杂的分配,例如:
let x =
let rec gcd a = function
| 0 -> a
| b -> gcd b (a % b)
gcd 10 25
编译器移动gcd
到私有成员,但将其嵌套在赋值中允许更严格的范围。另一方面,函数参数受到更多限制。它们不会创建新的范围(我知道),并且您不能将函数定义为例如表达式的一部分。
看起来像是缩进敏感解析器中的差异,而不是与这些运算符特别有关的任何事情。