为什么FSharp交互允许mutable let?

bra*_*ing 0 f# read-eval-print-loop

在FSI我输入

> let a = 10;;

val a : int = 10

> let a = a + 1;;

val a : int = 11
Run Code Online (Sandbox Code Playgroud)

看起来我在这里有一个可变变量?我错过了什么吗?

Art*_*CLI 5

它不是一个可变的值.但是您使用阴影:在F#中,当在特定范围内声明的变量(决策块,方法或内部类)与在外部范围中声明的变量具有相同的名称时,会发生值阴影.

如果你想要一个可变值,F#中有一个语法:

let mutable a = 10
a <- a + 1
Run Code Online (Sandbox Code Playgroud)


Tom*_*cek 5

正如Arthur已经解释的那样,你看到的是阴影,这意味着命名的原始"变量" a被一个也被命名的新"变量"隐藏a(我在引号中使用变量,因为它们实际上是不可变的值).

要查看差异,可以捕获函数中的原始值,然后在隐藏原始值后打印该值:

> let a = 10;;                // Define the original 'a' value
val a : int = 10

> let f () = a;;              // A function captures the original value    
val f : unit -> int

> let a = 42;;                // Define a new value hiding the first 'a'
val a : int = 42

> f();;                       // Prints the original value - it is not mutated!
val it : int = 10
Run Code Online (Sandbox Code Playgroud)

可悲的是,你不能使用完全相同的代码来看看如何let mutable行为(因为F#不允许捕捉封可变参考),但你可以看到突变,当您使用参考单元(即,一个简单的对象,在堆存储可变值):

> let a = ref 10;;             // Create a mutable reference cell initialized to 10
val a : int ref = {contents = 10;}

> let f () = !a;;              // A function reads the current value of the cell    
val f : unit -> int

> a := 42;;                    // Overwrite the value in the cell with 42
val it : unit = ()

> f();;                        // Prints the new value - it is mutated
val it : int = 42
Run Code Online (Sandbox Code Playgroud)

您可以在F#interactive中逐行运行代码,但是当您复制整个代码段(输入行)并将它们放在普通的F#代码中时,它会完全相同 - 例如在函数或模块中.这;;只是结束F#交互输入中的行(我在F#Interactive窗口中键入代码),但在普通代码中不需要它,因为F#使用缩进来找出语句结束的位置.