How do I create a partial function with generics in scala?

Posted by Matteo Caprari on Stack Overflow See other posts from Stack Overflow or by Matteo Caprari
Published on 2011-01-10T12:37:49Z Indexed on 2011/01/10 12:53 UTC
Read the original article Hit count: 416

Hello.

I'm trying to write a performance measurements library for Scala. My idea is to transparently 'mark' sections so that the execution time can be collected. Unfortunately I wasn't able to bend the compiler to my will.

An admittedly contrived example of what I have in mind:

// 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)
}

Now, this is the farthest I got:

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)
  }
}

Using the time function directly works and the compiler correctly uses the return type of the anonymous function to type the 'time' function:

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

Great as it seems, this pattern has a number of shortcomings:

  • forces the user to reuse the same symbol at each invocation
  • makes it more difficult to do more advanced stuff like predefined project-level timers
  • does not allow the library to initialize once a data structure for 'timerBigString

So here it comes mkTimer, that would allow me to partially apply the time function and reuse it. I use mkTimer like this:

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

But I get a compiler error:

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

I get the same error if I inline the currying:

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

This works if I do val timerBigString = time('timerBigString) (_: String), but this is not what I want. I'd like to defer typing of the partially applied function until application.

I conclude that the compiler is deciding the return type of the partial function when I first create it, chosing "Nothing" because it can't make a better informed choice.

So I guess what I'm looking for is a sort of late-binding of the partially applied function. Is there any way to do this? Or maybe is there a completely different path I could follow?

Well, thanks for reading this far

-teo

© Stack Overflow or respective owner

Related posts about scala

Related posts about anonymous-function