Why foldRight and reduceRight are NOT tail recursive?

前端 未结 2 881
遥遥无期
遥遥无期 2021-01-02 03:44

Why compiler does not translate Scala

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

to Java equivalent

final int[] intArray = new int[         


        
2条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-01-02 04:18

    (1, 2, 3, 4, 5, 6) is a 6 valued tuple, which doesn't have the foldRight, but Array(1, 2, 3, 4, 5, 6) does.

    ArrayLike is a trait subclassing indexed sequences with efficient element access, meaning it has certain methods optimized, including for instance foldRight. Each array is implicitly converted to a subclass of the ArrayLike trait. From Scala trunk:

      @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)
    

    Bytecode:

    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
    

    EDIT: The method in bytecode is iterative, meaning that the compiler must have applied a tail call optimization.

    Without efficient element access (i.e. an efficient apply method) the best one can do generically is using iterators and a non-tail recursive function to implement foldRight, or reversing the collection by building a new one and doing a foldLeft on that (the latter is done, currently). In the case of all sequences with efficient random access, this behaviour is overridden and optimized.

提交回复
热议问题