【问题标题】:F# Lazy Evaluation vs Non-LazyF# 惰性求值与非惰性求值
【发布时间】:2011-07-13 18:35:32
【问题描述】:

我刚刚开始 F#,所以如果这是基本的,请善待。

我读过一个标记为惰性的函数只被评估一次,然后被缓存。例如:

let lazyFunc = lazy (1 + 1)
let theValue = Lazy.force lazyFunc

与每次调用时实际运行的此版本相比:

let eagerFunc = (1 + 1)
let theValue = eagerFunc

基于此,所有函数是否应该变得惰性?你什么时候不想?这来自“Beginning F#”一书中的材料

【问题讨论】:

  • 这是什么版本的 F#?我有一个序列是懒惰的,但不是以这种方式公开创建的。我正在尝试强制它完成。

标签: f# lazy-evaluation


【解决方案1】:

首先,请注意,您定义的所有内容都不是函数 - eagerFunctheValueint 类型的值,lazyFunc 是 @987654325 类型的值@。给定

let lazyTwo = lazy (1 + 1)

let eagerTwo = 1 + 1

无论您使用多少次eagerTwo,表达式1 + 1 都将不会被多次评估。区别在于1 + 1 将在定义 eagerTwo精确 被评估一次,但在lazyTwo最多 被评估一次被使用(它将在第一次访问Value 属性时进行评估,然后缓存,以便Value 的进一步使用不需要重新计算它)。如果lazyTwoValue 从未被访问过,那么它的主体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

【讨论】:

  • 不使用() 暗示它是一个函数?无论如何都是好点。你说得对,我的例子非常琐碎。
  • @Yuck - 括号在不同的上下文中表示不同的含义。当您像(1 + 1) 一样使用它们时,它们仅用于指示分组和优先级。如果您已经定义了let eagerFunc() = ...,那么括号中的eagerFunc 是一个函数,但请注意这与您编写的不同。
【解决方案2】:

如果函数执行有副作用,并且每次调用函数时查看副作用很重要(比如它包装了一个 I/O 函数),你不希望它变得懒惰。

还有一些函数非常琐碎,以至于每次执行它们都比缓存值要快--

【讨论】:

    【解决方案3】:

    let eagerFunc = (1 + 1) 是一个 let 绑定,并且只会执行一次。 let eagerFunc() = (1 + 1) 是一个接受unit(无)并返回int 的函数。每次调用它都会执行。从某种意义上说,每个函数都是惰性的,也就是说,它只在被调用时执行。但是,lazy 关键字(以及它返回的System.Lazy)将最多执行一次给它的表达式/函数。对Value 属性的后续调用将返回缓存的结果。当值的计算很昂贵时,这很有用。

    许多函数不适合与lazy 一起使用,因为它们要么是不确定的(每次调用可能返回不同的结果),要么是参数化的。当然,可以使用此类函数的完全应用(为每个参数提供一个值)版本,但通常需要可变性。

    【讨论】:

      猜你喜欢
      • 2012-08-31
      • 1970-01-01
      • 2012-10-29
      • 2011-07-14
      • 1970-01-01
      • 1970-01-01
      • 2011-02-23
      • 2021-12-23
      • 2011-05-12
      相关资源
      最近更新 更多