F#惰性评估与非惰性评估
我才刚刚开始F#所以如果这是基本的,请客气一点 我已经读到,标记为lazy的函数只计算一次,然后缓存。例如:F#惰性评估与非惰性评估,f#,lazy-evaluation,F#,Lazy Evaluation,我才刚刚开始F#所以如果这是基本的,请客气一点 我已经读到,标记为lazy的函数只计算一次,然后缓存。例如: let lazyFunc = lazy (1 + 1) let theValue = Lazy.force lazyFunc 与每次调用时实际运行的此版本相比: let eagerFunc = (1 + 1) let theValue = eagerFunc 基于此,所有的函数都应该变为惰性吗?你什么时候不想去?这来自于《开始F#》一书中的内容。如果函数执行有副作用,并且每次调用函数
let lazyFunc = lazy (1 + 1)
let theValue = Lazy.force lazyFunc
与每次调用时实际运行的此版本相比:
let eagerFunc = (1 + 1)
let theValue = eagerFunc
基于此,所有的函数都应该变为惰性吗?你什么时候不想去?这来自于《开始F#》一书中的内容。如果函数执行有副作用,并且每次调用函数时都要看到副作用很重要(比如它包装了一个I/O函数),那么您不会希望它懒惰 还有一些函数非常简单,每次执行它们都比缓存值快--
let-quengefunc=(1+1)
是一个let绑定,只执行一次let func()=(1+1)
是一个接受单元
(无)并返回int
的函数。它将在每次调用时执行。从某种意义上说,每个函数都是惰性的,也就是说,它只在被调用时执行。但是,lazy
关键字(以及它返回的System.lazy
)将最多执行一次给定给它的表达式/函数。随后调用值
属性将返回缓存的结果。当值的计算非常昂贵时,这非常有用
许多函数不适合与
lazy
一起使用,因为它们要么是非确定性的(每次调用可能返回不同的结果),要么是参数化的。当然,可以使用这种函数的完全应用(为每个参数提供一个值)版本,但通常需要可变性。首先,请注意,您所定义的任何东西都不是函数-acengerfunc
和value
都是int
类型的值,lazyFunc
都是Lazy
类型的值。给定
let lazyTwo = lazy (1 + 1)
及
表达式1+1
将计算不超过一次,无论您使用两次。不同之处在于,定义2
时,1+1
将精确计算一次,但在使用lazytou
时最多计算一次(第一次访问值
属性时,将对其进行评估,然后缓存,以便值
的进一步使用不需要重新计算)。如果从未访问Lazytoo
的值
,则其主体1+1
将永远不会进行评估
通常,在严格的语言(如F#)中使用惰性值不会有多大好处。它们会增加少量开销,因为访问Value
属性需要检查该值是否已经计算过。如果您有类似let lazyValue=lazy someVeryExp的内容,它们可能会为您节省一些计算EnsiveCalculationAtMightNotBeneeed()
,因为昂贵的计算只会在实际使用该值的情况下进行。它们还可以使某些算法终止,否则不会终止,但这不是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
使用()
不是意味着它是一个函数吗?无论如何,这是好的。你是对的,我的例子非常简单。@恶心-括号在不同的上下文中意味着不同的东西。当你像(1+1)
那样使用它们时,它们只是用来表示分组和优先级。如果你已经定义了让func()=…
然后括号表示eangefunc
是一个函数,但请注意,这与您编写的不同。这是什么版本的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