我刚刚开始F#所以如果这是基本的话,请善待。
我已经读过标记为lazy的函数只被评估一次然后被缓存。例如:
let lazyFunc = lazy (1 + 1)
let theValue = Lazy.force lazyFunc
与每次调用时实际运行的版本相比:
let eagerFunc = (1 + 1)
let theValue = eagerFunc
基于此,所有函数应该变得懒惰吗?你什么时候不想?这来自书中的材料“Beginning F#”。
答案 0 :(得分:15)
首先,注意到您定义的所有内容都不是函数可能会有所帮助 - eagerFunc
和theValue
是类型int
和{{1}的值}是类型lazyFunc
的值。给定
Lazy<int>
和
let lazyTwo = lazy (1 + 1)
无论您使用let eagerTwo = 1 + 1
多少次,表达式1 + 1
都会不多次评估。不同之处在于,定义 eagerTwo
时,1 + 1
将被完全评估一次,但最多只会评估 当eagerTwo
使用时(将在第一次访问lazyTwo
属性时对其进行评估,然后进行缓存,以便进一步使用Value
不需要重新计算它)。如果永远不会访问Value
的{{1}},则其正文lazyTwo
永远不会进行评估。
通常情况下,在F#等严格语言中使用延迟值并不会带来太多好处。它们会增加少量开销,因为访问Value
属性需要检查该值是否已经计算过。如果您有类似1 + 1
的内容,它们可能会为您节省一些计算,因为只有在实际使用该值时才会进行昂贵的计算。它们也可以使一些算法终止,否则不会,但这不是F#中的主要问题。例如:
Value
答案 1 :(得分:6)
如果函数执行有副作用,每次调用函数时都会看到副作用很重要(比如它包装了I / O函数),你不会希望它是懒惰的。
还有一些功能非常简单,每次执行它们比缓存值更快 -
答案 2 :(得分:5)
let eagerFunc = (1 + 1)
是一个let绑定,只执行一次。 let eagerFunc() = (1 + 1)
是一个接受unit
(无)并返回int
的函数。它会在每次调用时执行。从某种意义上说,每个函数都是惰性的,也就是说,它只在被调用时执行。但是,lazy
关键字(和它返回的System.Lazy
)将执行最多一次给它的表达式/函数。对Value
属性的后续调用将返回缓存的结果。当计算值很昂贵时,这很有用。
许多函数不适合与lazy
一起使用,因为它们要么是非确定性的(可能在每次调用时返回不同的结果),要么参数化。当然,可以使用这些函数的完全应用(为每个参数提供一个值)版本,但通常需要可变性。