在F#核心库中,有一些高阶函数会接受重排(fun () -> ...
),但从概念上讲也可以接受Lazy<_>
,例如Option.defaultWith
。 F#通过Lazy<_>
关键字对lazy
具有良好的语法支持,但是我想不起来F#核心库中的任何函数都需要Lazy<_>
而不是thunk。我猜这是因为使用thunk比使用.NET特定的Lazy<_>
类型“更多的FP”。
但是除了模糊地“减少FP”之外:如果该值最多需要1次,那么使用Lazy<_>
而不是thunk的实际考虑是什么?例如,是否存在性能差异(CPU和/或分配/内存)?还有其他问题吗?用Lazy<_>
而不是笨拙可以更好地解决哪种情况?
答案 0 :(得分:9)
作为一个单独的对象,它包装了thunk,提供了同步并保存了结果引用,与简单的thunk相比,Lazy<_>
有一些额外的开销。
如果您知道(最多)只评估一次thunk,那么我认为没有理由不使用函数。您可以在另一个函数中包装对Lazy<_>
的{{1}}的调用,但是在这种情况下,我没有任何好处。
我记得一个Value
有用的情况是,我们的产品中有两个单独的功能标志,如果启用了这两个标志,都可能需要初始化Orleankka actor系统-昂贵的操作,每次应用程序启动时只能执行一次。
因此,我们的选项要么是很多嵌套的Lazy<_>
,要么是可变的选项,要么是:
if
与thunk不同,let actorSystem = lazy initializeActorSystem ()
if feature1Enabled then
let as = actorSystem.Value
...
if feature2Enabled then
let as = actorSystem.Value
...
还允许您检查thunk是否已评估。来自同一个实例:
Lazy<_>
通常情况下,如果您不确定一次最多可以评估一次thunk,尤其是可以同时发生的情况。我认为我们也有类似的用例,当未在本地同时提供给正在同时启动的多个组件时,可以读取一些外部配置-if actorSystem.IsValueCreated then
actorSystem.Value.Dispose()
确保无论哪个组件,我们都只能进行一次远程调用(如果需要的话)首先发现它需要它。