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
機能し、コンパイラは無名関数の戻り値の型を正しく使用して「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)
が、これは私が望むものではありません。部分的に適用された関数の入力を適用まで延期したいと思います。
私は、部分関数を最初に作成したときに、コンパイラが部分関数の戻り値の型を決定していると結論付けました。
だから私が探しているのは、部分的に適用された機能の一種の遅延バインディングだと思います。これを行う方法はありますか?それとも、私がたどることができるまったく別の道があるのでしょうか?
さて、ここまで読んでくれてありがとう
-テオ