14

我正在尝试学习函数式编程和 Scala,所以我正在阅读 Chiusano 和 Bjarnason 的“Scala 中的函数式编程”。在列表的情况下,我无法理解向左折叠和向右折叠方法的作用。我环顾四周,但没有找到适合初学者的东西。所以书上提供的代码是:

def foldRight[A,B](as: List[A], z: B)(f: (A, B) => B): B = as match {
  case Nil => z
  case Cons(h, t) => f(h, foldRight(t, z)(f))
}

def foldLeft[A,B](l: List[A], z: B)(f: (B, A) => B): B = l match {
  case Nil => z
  case Cons(h,t) => foldLeft(t, f(z,h))(f)
}

Cons 和 Nil 在哪里:

case class Cons[+A](head: A, tail: List[A]) extends List[A]
case object Nil extends List[Nothing]

那么左右折叠实际上是做什么的呢?为什么需要作为“实用”方法?还有许多其他使用它们的方法,我也很难理解它们,因为我不明白这两个。

4

2 回答 2

37

根据我的经验,锻炼直觉的最佳方法之一是在非常简单的示例中查看它是如何工作的:

List(1, 3, 8).foldLeft(100)(_ - _) == ((100 - 1) - 3) - 8 == 88
List(1, 3, 8).foldRight(100)(_ - _) == 1 - (3 - (8 - 100)) == -94

如您所见,foldLeft/Right只需将列表的元素和前一个应用程序的结果传递给第二个括号中的操作。还应该提到的是,如果您将这些方法应用于同一个列表,则仅当应用的操作是关联的时,它们才会返回相同的结果。

于 2016-11-28T11:43:22.057 回答
5

假设您有一个数字列表,并且您想将它们全部加起来。你会怎么做?您将第一个和第二个相加,然后取其结果,将其添加到第三个,取其结果,将其添加到第四个......等等。

这就是 fold 让你做的事情。

List(1,2,3,4,5).foldLeft(0)(_ + _)

“+”是您要应用的函数,第一个操作数是它应用到元素的结果,第二个操作数是下一个元素。由于您没有第一个应用程序的“迄今为止的结果”,因此您提供了一个起始值 - 在本例中为 0,因为它是添加的标识元素。

假设您想将所有列表元素与折叠相乘,那就是

List(1,2,3,4,5).foldLeft(1)(_ * _)

Fold 有它自己的维基百科页面,您可能想查看。

当然foldLeftfoldRight也有 ScalaDoc 条目。

于 2016-11-28T09:57:13.157 回答