2011-11-12 73 views
4

我提出的递归函数,就像斯卡拉有智能编译器?

require : L (List[Int]) 

L铜片匹配

  1. Nil => Thread.dumpStack()
  2. x :: xs => print(x) + function(xs)
def function(L : List[Int]) { 
    L match { 
     case Nil => Thread.dumpStack() 
     case x :: xs => print(x + " "); function(xs) 
    } 
} 

VAL L =(1〜5)。 toList // 功能(l)

所以我觉得在堆栈帧n次这样的功能,但它发生一次,我觉得这个功能已经找到Nil并打印出异常Thread.dumpStack

scala编译器是否聪明或其他?

+0

-1请更清楚:提供短代码样本和REPL抄本来说明问题。 – retronym

回答

7

您正在观察尾递归:从一次迭代到下一次迭代没有什么要存储的,所以递归本质上被编译器转化为一个while循环。 (所以,编译器就是这样聪明的。)

+0

啊哈,尾递归。 :) – Silvester

1

正如Rex Kerr指出的,这是应用尾部调用优化的Scala编译器。如果你想知道到底是编译的,你可以用一个额外的参数运行编译器:

scalac -Xprint:tailcalls yourfile.scala 

这将tailcalls编译阶段之后打印中间表示。在接下来的输入(如果您想了解所有阶段,还可以运行scalac -Xshow-phases)。例如,:

object TailRec { 
    def foo(l : List[Int]) : Unit = l match { 
    case Nil => Thread.dumpStack() 
    case x :: xs => println(x); foo(xs) 
    } 
} 

编译器将打印(用于功能foo):

def foo(l: List[Int]): Unit = { 
    <synthetic> val _$this: TailRec.type = TailRec.this; 
    _foo(_$this,l){ 
    l match { 
     case immutable.this.Nil => java.this.lang.Thread.dumpStack() 
     case (hd: Int, tl: List[Int])collection.immutable.::[Int]((x @ _), (xs @ _)) => { 
     scala.this.Predef.println(x); 
     _foo(TailRec.this, xs) 
     } 
    } 
    } 
} 

部分_foo(_$this,l)看起来像一个函数定义,但它实际上是一个标签,而“调用”_foo(TailRec.this, xs)实际上是跳转到该标签。简而言之,编译器将递归调用重新编写为真正的while循环。

编译器会在可以时自动应用优化。如果你想确保一个函数被正确地重写,你可以使用@tailrec对它进行注释,如果编译器不能优化它,编译器会产生一个错误。