F#惰性评估与非惰性 [英] F# Lazy Evaluation vs Non-Lazy
问题描述
我刚开始使用F#,所以如果这很简单,请保持警惕.
I'm just beginning F# so please be kind if this is basic.
我已经读过一个标记为lazy的函数只被评估一次,然后被缓存.例如:
I've read that a function marked lazy is evaluated only once and then cached. For example:
let lazyFunc = lazy (1 + 1)
let theValue = Lazy.force lazyFunc
与此版本相比,该版本实际上在每次调用时都会运行:
Compared to this version which would actually run each time it's called:
let eagerFunc = (1 + 1)
let theValue = eagerFunc
基于此,所有功能是否应该变得懒惰?您什么时候不想?这来自开始F#" 一书中的内容.
Based on that, should all functions be made lazy? When would you not want to? This is coming from material in the book "Beginning F#".
推荐答案
首先,可能要注意一点,您定义的所有内容都不是函数-eagerFunc
和theValue
都是类型的值int
和lazyFunc
是Lazy<int>
类型的值.给定
First of all, it may be helpful to note that none of the things you have defined is a function - eagerFunc
and theValue
are values of type int
and lazyFunc
is a value of type Lazy<int>
. Given
let lazyTwo = lazy (1 + 1)
和
let eagerTwo = 1 + 1
无论您使用eagerTwo
多少次,表达式1 + 1
都会不会被多次评估.区别在于1 + 1
在定义 eagerTwo
时将被精确评估一次,但是在lazyTwo
时将被评估一次 一次. 已使用(将在第一次访问Value
属性时进行评估,然后将其缓存,以便Value
的进一步使用不需要重新计算它).如果lazyTwo
的Value
从未被访问过,则其主体1 + 1
将从不被评估.
the expression 1 + 1
will not be evaluated more than once no matter how many times you use eagerTwo
. The difference is that 1 + 1
will be evaluated exactly once when defining eagerTwo
, but will be evaluated at most once when lazyTwo
is used (it will be evaluated the first time that the Value
property is accessed, and then cached so that further uses of Value
do not need to recalculated it). If lazyTwo
's Value
is never accessed, then its body 1 + 1
will never be evaluated.
通常,以严格的语言(例如F#)使用懒惰值不会带来太大好处.由于访问Value
属性需要检查该值是否已计算,因此它们会增加少量开销.如果您使用类似let lazyValue = lazy someVeryExpensiveCalculationThatMightNotBeNeeded()
的方法,它们可能会为您节省一些计算时间,因为昂贵的计算仅在实际使用该值的情况下才会进行.他们还可以使某些算法终止,否则将无法终止,但这在F#中不是主要问题.例如:
Typically, you won't see much benefit to using lazy values in a strict language like F#. They add a small amount of overhead since accessing the Value
property requires checking whether the value has already been calculated. They might save you a bit of calculation if you have something like let lazyValue = lazy someVeryExpensiveCalculationThatMightNotBeNeeded()
, since the expensive calculation will only take place if the value is actually used. They can also make some algorithms terminate which otherwise would not, but this is not a major issue in F#. For instance:
// throws an exception if x = 0.0
let eagerDivision x =
let oneOverX = 1.0 / x
if x = 0.0 then
printfn "Tried to divide by zero" // too late, this line is never reached
else
printfn "One over x is: %f" oneOverX
// succeeds even if x = 0.0, since the quotient is lazily evaluated
let lazyDivision x =
let oneOverX = lazy (1.0 / x)
if x = 0.0 then
printfn "Tried to divide by zero"
else
printfn "One over x is: %f" oneOverX.Value
这篇关于F#惰性评估与非惰性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!