为什么F#Interactive在不可变值定义方面的行为与编译器不同?

Guy*_*der 5 f# immutability f#-interactive

在阅读John Palmer的答案时,可变值与不可变值重新定义之间的区别是什么?,约翰指出

这种重新定义只适用于fsi.

在使用F#Interactive(fsi)时,我想我下意识地知道它,但从未注意过它.

现在很明显,为什么差异?

更具体地说,请解释fsi和编译器之间的内部结构是如何不同的,这是通过设计或差异的结果发生的?

如果答案可以详细说明持有绑定的内部结构,那将是值得赞赏的.

Ste*_*sen 5

语义与FSI将交互式提交编译到FSI会话的方式一致:每个交互式提交都被编译为module对后续交互式提交开放.

以下内容与FSI的实际内容非常接近,并说明了绑定阴影如何在交互式提交中起作用:

FSI提交#1: let x = 1;;

module FSI_1 = 
    let x = 1

open FSI_1 //FSI_1.x is now bound to 1 and available at the top level
Run Code Online (Sandbox Code Playgroud)

FSI提交#2: let x = 2;;

module FSI_2 = 
    let x = 2

open FSI_2 //FSI_1.x is now shadowed by FSI_2.x which is bound to 2 and available at the top level
Run Code Online (Sandbox Code Playgroud)

您可以通过FSI_ASSEMBLY在FSI应用程序域中使用程序集上的反射来查看动态FSI程序集的编译方式的实际细节.每个交互式提交都是作为一个带有命名模式的模块(.NET类)发出的FSI_####.FsEye使用这些事实来发现FSI顶级绑定的状态:https://code.google.com/p/fseye/source/browse/tags/2.0.1/FsEye/Fsi/SessionQueries.fs#24

关于@ JohnPalmer的答案的关键点是顶层FSI定义不能被改变,当它们被"重新定义"时它们只是被遮蔽.我们可以这样说明如下:

> let x = 1;; //our original definition of x
val x : int = 1

> let f () = x;; //capture x
val f : unit -> int

> let x = 2;; //shadow our original definition of x
val x : int = 2

> f();; //returns the original x value, which is still 1 rather than 2
val it : int = 1
Run Code Online (Sandbox Code Playgroud)

  • 对于那些不熟悉[FsEye](https://code.google.com/p/fseye/source/browse/tags/2.0.1/FsEye/)的人,你应该至少使用一次才能看到它它是如何以及它如何帮助你.我很少使用它,但是当我需要它时,没有其他任何东西可以正常工作.谢谢Stephen! (2认同)