2011-01-10 52 views
7

我正在嘗試爲Scala編寫一個性能測量庫。我的想法是透明地「標記」部分,以便可以收集執行時間。不幸的是,我無法按照自己的意願彎曲編譯器。如何在scala中使用泛型創建部分函數?

的什麼,我心目中無可否認人爲的例子:

// generate a timing function 
val myTimer = mkTimer('myTimer) 

// see how the timing function returns the right type depending on the 
// type of the function it is passed to it 
val act = actor { 
    loop { 
     receive { 

      case 'Int => 
       val calc = myTimer { (1 to 100000).sum } 
       val result = calc + 10 // calc must be Int 
       self reply (result) 

      case 'String => 
       val calc = myTimer { (1 to 100000).mkString } 
       val result = calc + " String" // calc must be String 
       self reply (result) 
} 

現在,這是我得到的最遠:

trait Timing { 
    def time[T <: Any](name: Symbol)(op: => T) :T = { 
     val start = System.nanoTime 
     val result = op 
     val elapsed = System.nanoTime - start 
     println(name + ": " + elapsed) 
     result 
    } 

    def mkTimer[T <: Any](name: Symbol) : (() => T) =>() => T = { 
     type c =() => T 
     time(name)(_ : c) 
    } 
} 

使用time功能直接和編譯器能夠正確使用返回鍵入「時間」功能的匿名函數:

val bigString = time('timerBigString) { 
    (1 to 100000).mkString("-") 
} 
println (bigString) 

大,因爲它似乎,這種模式有許多缺點:

  • 迫使用戶在每次調用
  • 使之更難以做到像預定義的項目級定時器
  • 更先進的東西重複使用相同的符號
  • 不允許圖書館所以這裏初始化一次數據結構「timerBigString

談到mkTimer,這將讓我部分應用時功能和重用。我用mkTimer這樣的:

val myTimer = mkTimer('aTimer) 
val myString= myTimer { 
    (1 to 100000).mkString("-") 
} 
println (myString) 

但我得到一個編譯器錯誤:

error: type mismatch; 
found : String 
required:() => Nothing 
(1 to 100000).mkString("-") 

我得到同樣的錯誤,如果我行內的柯里:

val timerBigString = time('timerBigString) _ 
val bigString = timerBigString { 
    (1 to 100000).mkString("-") 
} 
println (bigString) 

這個作品,如果我這樣做val timerBigString = time('timerBigString) (_: String),但這不是我想要的。我想推遲部分應用函數的打字,直到應用程序。

我斷定編譯器在我第一次創建時決定部分函數的返回類型,選擇「Nothing」是因爲它無法做出更好的知情選擇。

所以我想我正在尋找的是一種部分應用函數的後期綁定。有沒有辦法做到這一點?或者,我可以遵循完全不同的路線嗎?

好了,感謝您閱讀本遠

-TeO

回答

7

了以往的模式,當你想「偷懶」仿製藥是使用一類具有的適用方法

class Timer(name: Symbol) { 
    def apply[T](op: => T) = time(name)(op) 
} 
def mkTimer(name: Symbol) = new Timer(name) 
+0

點上!謝謝。 – 2011-01-10 12:54:36