Другие постеры дали хорошие ответы, и я не буду повторять то, что они уже сказали. Поскольку вы привели пример 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, foldRight
может легко взорвать стек для больших списков, а 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. В противном случае следуйте другим советам, данным в ответах;).