2013-10-11 98 views
3

我運行該程序使用Scala 2.10.3:爲什麼Scala中的這個函數調用沒有被優化掉?

object Test { 
    def main(args: Array[String]) { 
    def factorial(x: BigInt): BigInt = 
     if (x == 0) 1 else x * factorial(x - 1) 

    val N = 1000 
    val t = new Array[Long](N) 
    var r: BigInt = 0 

    for (i <- 0 until N) { 
     val t0 = System.nanoTime() 

     r = r + factorial(300) 
     t(i) = System.nanoTime()-t0 
    } 

    val ts = t.sortWith((x, y) => x < y) 

    for (i <- 0 to 10) 
     print(ts(i) + " ") 

    println("*** " + ts(N/2) + "\n" + r) 
    } 
} 

和呼叫到一個純函數factorial與常變量每次循環迭代(基於定時結果結論)期間被評估。優化器不應該在第一次調用之後重用函數調用結果嗎?

我正在使用Eclipse的Scala IDE。是否有編譯器的優化標誌,這可能會產生更有效的代碼?

+0

編譯器如何知道它是一個純函數? – pedrofurla

+0

如果'BigInt'上的'*'是純的,'factorial'是純的。我花了一天的時間閱讀Scala編程,所以我的知識在Scala編譯器的主題上太過薄弱。我的主要觀點是,LLVM編譯的類似C++或D代碼將重複調用具有常量參數優化的函數。 –

+0

@PaulJurczak順便說一句,你能提供一些關於LLVM中的優化的文章,論文或者一些鏈接嗎?我的意思是*由LLVM編譯的C++或D中的類似代碼將重複調用具有常量參數優化的函數* –

回答

6

Scala不是純粹的函數式語言,所以沒有效果系統,它不知道factorial是純粹的(例如,它不會「知道」任何關於大整數乘法的東西)。

您需要在這裏添加自己的memoization方法。大多數情況下只需在循環外部添加val f300 = factorial(300)即可。


Here is a question about memoization

+1

有沒有辦法讓Scala編譯器知道'factorial'是純粹的(或純粹的)? –

+2

@PaulJurczak沒有簡單的方法,除非你自己做所有的工作或插入一些編譯器插件。這也是另一個原因 - 與編譯語言如C++或C不同,Scala和Java編譯器在編譯期間不會執行積極的優化 - 他們推遲了大多數複雜的優化,希望JIT能夠做到這一點。 –

+1

Scala有[效果插件](http://lrytz.github.io/slides/lamp-lara-efftp.html#/),但是當「類型檢查」你的效果是正確組成的時候,它不會嘗試處理諸如記憶功能值之類的優化。或許你可以在函數中加入一個@ memoize宏,並且要求它們也是'@ pure' ... –

相關問題