懒惰的折扣,提前终止混乱

时间:2013-06-27 05:46:28

标签: scala functional-programming lazy-evaluation fold

在浏览Functional Programming in Scala时,我遇到了以下代码段:

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来看到这一点   实现exists,它检查Stream中是否有任何值   匹配给定的谓词。

然后作者陈述如下:

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

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

1 个答案:

答案 0 :(得分:6)

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,永远不会对其进行评估。这就是运算符的工作方式。

所以说适用于某些exists的{​​{1}}。对于第一个元素,将存在(其中Stream为真)此代码:

p(h)

与此代码相同(我们假设我们有一个非空流,所以我们可以删除第二种情况):

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,因此提前终止!