【问题标题】:Lazy foldRight early termination confusionLazy foldRight 提前终止混淆
【发布时间】:2013-06-27 05:46:28
【问题描述】:

在查看Functional Programming in Scala 时,我遇到了以下代码 sn-p:

def foldRight[A](z: => B)(f: (A,=>B) => B):B = uncons match {
  case Some((h,t)) => f(h,t.foldRight(z)(f))
  case None => z 
}

然后作者继续陈述以下内容:

这看起来与我们为 List 编写的 foldRight 非常相似,但是 注意我们的组合函数 f 在它的第二个中是非严格的 范围。如果 f 选择不计算它的第二个参数,这 提前终止遍历。我们可以通过使用 foldRight 来看到这一点 实现存在,它检查流中是否有任何值 匹配给定的谓词。

然后作者陈述如下:

def exists(p: A => Boolean): Boolean =
  foldRight(false)((a, b) => p(a) || b)

我的问题是组合函数 f 如何导致 exists 方法提前终止?我认为我无法从文本中理解这是如何发生的。

【问题讨论】:

    标签: scala functional-programming lazy-evaluation fold


    【解决方案1】:

    f(h,t.foldRight(z)(f)) 中,提供给f 的第一个参数是h,第二个参数是t.foldRight(z)(f)。定义foldRight 的方式是,它的f 参数的第二个参数是一个别名参数,在需要之前不会被评估(并且每次需要时都会被评估)。所以在f: (A, =>B) => B 中,A 类型的第一个参数是一个普通参数,而B 类型的第二个参数是一个别名参数。

    假设你这样定义f

    f(a: A, b: => Boolean): Boolean = predicate(a) || b
    

    如果predicate(a) 为真,则永远不需要b,也永远不会被评估。这就是 or 运算符的工作方式。

    所以说exists 应用于一些Stream。对于将 存在p(h) 为真)的 first 元素是 uncons-ed,此代码:

    uncons match {
      case Some((h,t)) => f(h,t.foldRight(z)(f))
      case None => z 
    }
    

    和这段代码一样(我们假设我们有一个非空流,所以我们可以去掉第二种情况):

    f(h,t.foldRight(z)(f))
    

    这相当于(扩展f):

    p(h) || t.foldRight(z)(f)
    

    但是p(h) 是这样的:

    true || t.foldRight(z)(f)
    

    这与true 相同,无需继续调用foldRight,因此会提前终止!

    【讨论】:

    • @huynhji - 有道理。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-04
    • 2017-03-11
    相关资源
    最近更新 更多