其他海报给出了很好的答案,我不再重复他们已经说过的话。正如您在问题中给出的Scala示例一样,我将给出一个Scala特定示例。正如Tricks所说的那样,foldRight
需要保留n-1
堆栈帧,n
列表的长度在哪里,这很容易导致堆栈溢出-甚至尾递归也不能使您免于此。
A List(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)中,a foldRight
可以轻松炸毁大型列表,而a foldLeft
则不会。
例:
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中始终使用。否则,请参考答案中给出的其他建议;)。