在阅读John Palmer对可变值和不可变值重新定义之间的区别的回答时?,John注意到
这种重新定义只适用于fsi。
在F#Interactive(fsi)的工作中,我想我下意识地知道它,但从未注意到它。
既然已经很明显了,为什么会有区别?
更具体地说,请解释fsi和编译器之间的内部结构是如何不同的,这是由于设计还是差异的结果?
如果答案能够详细说明包含绑定的内部结构,我们将不胜感激。
语义与FSI将交互式提交编译到FSI会话的方式一致:每个交互式提交都编译为module
,对后续的交互式提交开放。
以下内容接近FSI的实际操作,并说明了let绑定阴影是如何在交互式提交中工作的:
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
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
您可以看到如何通过在FSI应用程序域中的FSI_ASSEMBLY
程序集上使用反射来编译动态FSI程序集的实际详细信息。每个交互式提交都是作为一个模块(.NET类)发出的,命名模式为FSI_####
。FsYe使用以下事实来发现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