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



在阅读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

最新更新