2011-11-12 71 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對它進行註釋,如果編譯器不能優化它,編譯器會產生一個錯誤。