Мой scala-код не получает TCO'а, хотя он проходит @tailrec - PullRequest
5 голосов
/ 22 ноября 2011

Я смотрю в scala TCO и написал следующий код

import scala.annotation.tailrec
final def tailReccursionEx(str:String):List[String]={

  @tailrec 
  def doTailRecursionEx(str:String,pos:Int,accu:List[String]):List[String]={
    if(pos==str.length) return accu
    else{
      doTailRecursionEx(str,pos+1,accu++accu.foldLeft(List[String](str(`pos`).toString)){
                                            (l,ch)=>l:+ch+str(`pos`)})
  }
}

  doTailRecursionEx(str,0,List[String]())
}

Я прошел тест @tailrec и считаю, что моя функция является саморекурсивным хвостовым вызовом. Тем не менее, когда я смотрю в байт-код Java с

javap -c -private RecursionEx\$\$anonfun\$doTailRecursionEx\$1\$1

Я не вижу обещанного Перейти для TCO для саморекурсивной функции. Вот байт-код.

public RecursionEx$$anonfun$doTailRecursionEx$1$1(java.lang.String, int);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield    #35; //Field str$2:Ljava/lang/String;
   5:   aload_0
   6:   iload_2
   7:   putfield    #41; //Field pos$1:I
   10:  aload_0
   11:  invokespecial   #93; //Method scala/runtime/AbstractFunction2."<init>":()V
   14:  return

}

1 Ответ

10 голосов
/ 22 ноября 2011

Я думаю, вам нужно запустить javap для другого сгенерированного файла класса. Файл, который вы проверяете в настоящее время, соответствует закрытию, которое вы используете как часть foldLeft. Если вы попытаетесь просмотреть файл RecursionEx $ .class, вы увидите рекурсию хвостового вызова. Когда я компилирую код:

import scala.annotation.tailrec

object RecursionEx {
    @tailrec
    final def doTailRecursionEx(str: String, pos: Int, accu: List[String]): List[String] = {
        if (pos == str.length) return accu
        doTailRecursionEx(str, pos + 1 , accu ++ accu.foldLeft(List[String](str(`pos`).toString)) {
                            (l, ch) => l :+ ch + str(`pos`)
                        })
    }
    def main(args: Array[String]) {
        doTailRecursionEx("mew",0,List[String]())
    }
}

и затем запустите javap -c -private RecursionEx$ Я вижу следующее для соответствующего раздела кода:

public final scala.collection.immutable.List doTailRecursionEx(java.lang.String, int, scala.collection.immutable.List);

  Code:
   0:   iload_2
   1:   aload_1
   2:   invokevirtual   #21; //Method java/lang/String.length:()I
   5:   if_icmpne   10
   8:   aload_3
   9:   areturn
   10:  iload_2
   11:  iconst_1
   12:  iadd
   13:  aload_3
   14:  aload_3
   15:  getstatic   #26; //Field scala/collection/immutable/List$.MODULE$:Lscala/collection/immutable/List$;
   18:  getstatic   #31; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   21:  iconst_1
   22:  anewarray   #17; //class java/lang/String
   25:  dup
   26:  iconst_0
   27:  getstatic   #31; //Field scala/Predef$.MODULE$:Lscala/Predef$;
   30:  aload_1
   31:  invokevirtual   #35; //Method scala/Predef$.augmentString:(Ljava/lang/String;)Lscala/collection/immutable/StringOps;
   34:  iload_2
   35:  invokeinterface #41,  2; //InterfaceMethod scala/collection/immutable/StringLike.apply:(I)C
   40:  invokestatic    #47; //Method scala/runtime/BoxesRunTime.boxToCharacter:(C)Ljava/lang/Character;
   43:  invokevirtual   #53; //Method java/lang/Object.toString:()Ljava/lang/String;
   46:  aastore
   47:  checkcast   #55; //class "[Ljava/lang/Object;"
   50:  invokevirtual   #59; //Method scala/Predef$.wrapRefArray:([Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
   53:  invokevirtual   #62; //Method scala/collection/immutable/List$.apply:(Lscala/collection/Seq;)Lscala/collection/immutable/List;
   56:  new #64; //class RecursionEx$$anonfun$doTailRecursionEx$1
   59:  dup
   60:  aload_1
   61:  iload_2
   62:  invokespecial   #67; //Method RecursionEx$$anonfun$doTailRecursionEx$1."<init>":(Ljava/lang/String;I)V
   65:  invokeinterface #73,  3; //InterfaceMethod scala/collection/LinearSeqOptimized.foldLeft:(Ljava/lang/Object;Lscala/Function2;)Ljava/lang/Object;
   70:  checkcast   #75; //class scala/collection/TraversableOnce
   73:  getstatic   #26; //Field scala/collection/immutable/List$.MODULE$:Lscala/collection/immutable/List$;
   76:  invokevirtual   #79; //Method scala/collection/immutable/List$.canBuildFrom:()Lscala/collection/generic/CanBuildFrom;
   79:  invokevirtual   #85; //Method scala/collection/immutable/List.$plus$plus:(Lscala/collection/TraversableOnce;Lscala/collection/generic/CanBuildFrom;)Ljava/lang/Object;
   82:  checkcast   #81; //class scala/collection/immutable/List
   85:  astore_3
   86:  istore_2
   87:  goto    0

с goto в конце, как и следовало ожидать.

...