scala - 为什么 foldRight 和 reduceRight 不是尾递归的?

标签 scala functional-programming

为什么编译器不翻译 Scala

(1,2,3,4,5,6).foldRight(10)(_ * _)

相当于 Java
final int[] intArray = new int[]{1,2,3,4,5,6};
int accumulator = 10;

for(int i = intArray.legth - 1; i >=0; i--) {
  accumulator = intArray[i] * accumulator;
}

问题是:为什么 foldLeft 和 reduceLeft 是尾递归的,但它们的右对应部分不是?

这里是说右手不是尾递归的链接。我在问为什么会这样。

How do you know when to use fold-left and when to use fold-right?

Implications of foldr vs. foldl (or foldl')

http://programming-scala.labs.oreilly.com/ch08.html

最佳答案

(1, 2, 3, 4, 5, 6)是一个 6 值元组,它没有 foldRight ,但是 Array(1, 2, 3, 4, 5, 6)做。
ArrayLike是具有有效元素访问的特征子类索引序列,这意味着它优化了某些方法,包括例如 foldRight .每个数组都隐式转换为 ArrayLike 的子类特征。从 Scala 主干:

  @tailrec
  private def foldr[B](start: Int, end: Int, z: B, op: (A, B) => B): B =
    if (start == end) z
    else foldr(start, end - 1, op(this(end - 1), z), op)

字节码:
private static java.lang.Object foldr(scala.collection.IndexedSeqOptimized, int, int, java.lang.Object, scala.Function2);

...

  Code:
   Stack=6, Locals=6, Args_size=5
   0:   iload_1
   1:   iload_2
   2:   if_icmpne   7
   5:   aload_3
   6:   areturn
   7:   aload_0
   8:   iload_2
   9:   iconst_1
   10:  isub
   11:  aload   4
   13:  aload_0
   14:  iload_2
   15:  iconst_1
   16:  isub
   17:  invokeinterface #21,  2; //InterfaceMethod scala/collection/SeqLike.apply:(I)Ljava/lang/Object;
   22:  aload_3
   23:  invokeinterface #72,  3; //InterfaceMethod scala/Function2.apply:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   28:  astore_3
   29:  istore_2
   30:  astore_0
   31:  goto    0
  LineNumberTable: 
   line 68: 0
   line 67: 6
   line 69: 7

编辑:字节码中的方法是迭代的,这意味着编译器必须应用尾调用优化。

如果没有有效的元素访问(即有效的 apply 方法),一般可以做的最好的事情是使用迭代器和非尾递归函数来实现 foldRight ,或者通过构建一个新集合并执行 foldLeft 来反转集合对此(后者已完成,目前)。在所有序列都具有高效随机访问的情况下,此行为将被覆盖和优化。

关于scala - 为什么 foldRight 和 reduceRight 不是尾递归的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4085118/

相关文章:

scala - 如何组合两个 Future[JsArray]?

scala 获取作为参数发送的函数名称

scala - 猫 EitherT 和效果的匹配器

javascript - 为什么在字符串数组上使用 Array.map(parseInt) 会产生不同的结果

javascript - 使用函数式编程平均二维数组中的列

scala - 如何以功能风格粗化(而不是扁平化)列表?

java - Scala Play Framework 和 NIO.2

scala - 为什么 IDEA 10 中的控制台会以 "tools is not a member of package scala"失败?

haskell - 为什么惰性评估有用?

algorithm - 如何使用第一个 map 的值检索嵌套 map 的值?