たらいまわし問題(遅延評価編)

前エントリーで「scalaの遅延評価は限定的scalaなので無理かも」と書いたけれど嘘でした。
Scala開眼の引数の遅延評価渡しを参考にしたらできました。
以下がソース。

package tarai

import java.util.Calendar
import scala.collection.mutable.Map

object Main {
  def main(args: Array[String]): Unit = {
    val tm1 = Calendar.getInstance().getTimeInMillis
    println("result", taraiC(20, 10, 5))
    val tm2 = Calendar.getInstance().getTimeInMillis
    println("time", tm2 - tm1)
    println("result", taraiL(20, 10, 5))
    val tm3 = Calendar.getInstance().getTimeInMillis
    println("time", tm3 - tm2)
  }

  // たらいまわし(キャッシュ使用)
  var cache = Map.empty[Tuple3[Int, Int, Int], Int]
  def taraiC(x:Int, y:Int, z:Int): Int = {
    if (cache.contains((x,y,z)))
      cache((x,y,z))
    else {
      val result =
        if (x <= y) y
        else taraiC(taraiC(x - 1, y, z), taraiC(y - 1, z, x), taraiC(z - 1, x, y))
      cache((x,y,z)) = result
      result
    }
  }

  // たらいまわし(遅延評価)
  def taraiL(x: => Int, y: => Int, z: => Int): Int = {
    if (x <= y) y
    else taraiL(taraiL(x - 1, y, z),
                taraiL(y - 1, z, x),
                taraiL(z - 1, x, y))
  }
}

taraiLは遅延評価をしています。
このコードで、前エントリーのキャッシュを使った場合(taraiC)とどちらが速いか比較したのですが、自分の環境ではキャッシュ版が125ms,遅延評価版が16msでした。
しかし、taraiLをtaraiCより先に実行するようにしたら、キャッシュ版が15ms,遅延評価版が125msで逆転しました。
色々試したらprintlnの処理が初回時に時間がかかるようなので、mainの先頭にprintln("",0)を挿入すると、処理順序によらずtaraiCが16ms,taraiLが0msで処理をしました。