Geo*_*rgS 11 .net f# lazy-evaluation .net-framework-version
我刚刚在F#中编译这段代码时遇到了框架版本之间行为的变化:
let test = Lazy.CreateFromValue 1
Run Code Online (Sandbox Code Playgroud)
针对.NET framework 2.0编译,表达式导致"已创建"的Lazy对象,即:
test.IsValueCreated = true
Run Code Online (Sandbox Code Playgroud)
在针对.NET framework 4.0编译时,表达式会产生一个"未评估"的惰性对象,即:
test.IsValueCreated = false
Run Code Online (Sandbox Code Playgroud)
只有在后一种情况下访问test.Value之后,两者才是等价的.
我无法在任何地方找到任何关于这种变化的参考,因此我的问题是为什么这种变化表现不同以及变化背后的原因是什么(它正在破裂).在我看来,.NET 2.0中的行为更有意义 - 从具体值创建一个Lazy对象应该导致"已经评估"的惰性对象.
scr*_*wtp 14
在.NET 4.0之前,框架没有附带Lazy<'T>.
这是古老的历史,但F#最初有自己的实现Lazy,与我们今天的不同 - 你可以在这里看到它.
当很明显Lazy正在适应框架时,该实施就被放弃了.相反,F#2.0 System.Lazy<'T>在FSharp.Core程序集中附带了自己的(注意命名空间)实现.这是你仍然可以在这里看到的实现.这个想法是,一旦.NET 4.0可用,F#System.Lazy<'T>将从那里无缝地接收,而不会打破用户.这在很大程度上起作用,但并非完全没有问题.
您会注意到F#实现有一个CreateFromValue成员,它产生的类型值Lazy<'T>已标记为已评估.这在语义上是完全有意义的,因为你显然首先给它一个评估值.
那么为什么.NET 4.0实现不会这样做呢?
如果你看一下文件的Lazy<'T>,你会发现,有没有在评估状态创建它的方式.有没有CreateFromValue在上面成员,没有构造函数接受的值'T,只有一个Func<'T>.CreateFromValue实际上是由F#作为扩展方法提供的.
以非破坏的方式提供此方法非常容易:
static member CreateFromValue(value : 'T) : System.Lazy<'T> =
let x = System.Lazy<'T>.Create(fun () -> value)
x.Value |> ignore
x
Run Code Online (Sandbox Code Playgroud)
但这并没有因某种原因发生.也许这是一个刻意的选择 - 我想你可以支持和反对这种改变 - 但也许这是一种疏忽.如果你看一下这种令人费解的历史,我想你会同意它可能会更糟.