F#懒惰评估与非懒惰
我刚刚开始F#所以请善待,如果这是基本的。F#懒惰评估与非懒惰
我读过一个标记为lazy的函数只计算一次,然后缓存。例如:
let lazyFunc = lazy (1 + 1)
let theValue = Lazy.force lazyFunc
比起这个版本这将每次叫时间实际运行:
let eagerFunc = (1 + 1)
let theValue = eagerFunc
此基础上,应所有功能进行懒惰?你什么时候不想?这是来自“Beginning F#”一书中的内容。
首先,它可能是有益的注意,所有已定义的东西是一个功能 - eagerFunc
和theValue
是类型的值int
和lazyFunc
是Lazy<int>
类型的值。鉴于
let lazyTwo = lazy (1 + 1)
和
let eagerTwo = 1 + 1
表达1 + 1
将不评估一次以上,无论你有多少次使用eagerTwo
。所不同的是1 + 1
将被评估恰好一次时限定eagerTwo
,但将被评估至多一次时lazyTwo
是使用(它会在第一时间被评价为Value
属性被访问,并然后缓存以便进一步使用Value
不需要重新计算它)。如果lazyTwo
的Value
从未访问,那么它的身体1 + 1
将永远进行评估。
通常情况下,在F#等严格语言中使用惰性值时看不到太多好处。由于访问Value
属性需要检查值是否已经计算,因此它们会添加少量开销。如果您有类似let lazyValue = lazy someVeryExpensiveCalculationThatMightNotBeNeeded()
的东西,它们可能会为您节省一些计算费用,因为只有在实际使用该值时才会发生昂贵的计算。他们也可以使一些算法终止,否则不会,但这不是F#中的主要问题。例如:
// 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
如果函数执行有副作用,看到的副作用每个函数被调用的时间是很重要的(说包装了一个I/O功能),你不会希望它是懒惰。
也有这么琐碎的是,执行他们每个时间比缓存value--
let eagerFunc = (1 + 1)
快是让约束力,并且将只执行一次的功能。 let eagerFunc() = (1 + 1)
是接受unit
(无)并返回int
的函数。它会在每次调用时执行。从某种意义上说,每个函数都是懒惰的,也就是说,它只在被调用时执行。然而,lazy
关键字(和它返回的System.Lazy
)将最多执行一次赋予它的表达式/函数。随后调用Value
属性将返回缓存的结果。这在计算价值昂贵时很有用。
许多功能将不适合与lazy
一起使用,因为它们要么是非确定性的(可能会在每次调用时返回不同的结果)或参数化的。当然,可以使用这些函数的完全应用(为每个参数提供值)版本,但通常需要可变性。
这是什么版本的F#?我有一个懒惰行事的序列,但并没有公开这样创建。我试图强制它完成。 – octopusgrabbus