其他海报已经给出了很好的答案,我不会重复他们已经说过的话。正如您在问题中给出了一个 Scala 示例,我将给出一个 Scala 特定示例。正如Tricks已经说过的那样,foldRight
需要保留n-1
堆栈帧,n
列表的长度在哪里,这很容易导致堆栈溢出 - 甚至尾递归也不能让你摆脱这种情况。
AList(1,2,3).foldRight(0)(_ + _)
将减少为:
1 + List(2,3).foldRight(0)(_ + _) // first stack frame
2 + List(3).foldRight(0)(_ + _) // second stack frame
3 + 0 // third stack frame
// (I don't remember if the JVM allocates space
// on the stack for the third frame as well)
而List(1,2,3).foldLeft(0)(_ + _)
将减少为:
(((0 + 1) + 2) + 3)
可以迭代计算,就像在 的实现中List
所做的那样。
在像 Scala 这样严格评估的语言中,afoldRight
可以轻松地将堆栈用于大型列表,而 afoldLeft
不会。
例子:
scala> List.range(1, 10000).foldLeft(0)(_ + _)
res1: Int = 49995000
scala> List.range(1, 10000).foldRight(0)(_ + _)
java.lang.StackOverflowError
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRight(List.scala:1081)
at scala.List.foldRig...
因此,我的经验法则是 - 对于没有特定关联性的运算符,请始终使用foldLeft
,至少在 Scala 中是这样。否则,请参考答案中给出的其他建议;)。