lundi 20 avril 2015

How to "extract" type parameter to instantiate another class

The following Scala code works:

object ReducerTestMain extends App {

  type MapOutput = KeyVal[String, Int]

  def mapFun(s:String): MapOutput = KeyVal(s, 1)

  val red = new ReducerComponent[String, Int]((a: Int, b: Int) => a + b)

  val data = List[String]("a", "b", "c", "b", "c", "b")

  data foreach {s => red(mapFun(s))}
  // OUTPUT: Map(a -> 1, b -> 3, c -> 2)

class ReducerComponent[K, V](f: (V, V) => V) {
  var mem = Map[K, V]()

  def apply(kv: KeyVal[K, V]) = {
    val KeyVal(k, v) = kv
    mem += (k -> (if (mem contains k) f(mem(k), v) else v))

case class KeyVal[K, V](key: K, value:V)

My problem is I would like to instantiate ReducerComponent like this:

val red = new ReducerComponent[MapOutput, Int]((a: Int, b: Int) => a + b)

or even better:

val red = new ReducerComponent[MapOutput](_ + _)

That means a lot of things:

  1. I would like to type-check that MapOutput is of the type KeyVal[K, C],
  2. I want to type-check that C is the same type used in f,
  3. I also need to "extract" K in order to instantiate mem, and type-check parameters from apply.

Is it a lot to ask? :) I wanted to write something like

class ReducerComponent[KeyVal[K,V]](f: (V, V) => V) {...}

By the time I will instantiate ReducerComponent all I have is f and MapOutput, so inferring V is OK. But then I only have KeyVal[K,V] as a type parameter from a class, which can be different from KeyVal[_,_].

I know what I'm asking is probably crazy if you understand how type inference works, but I don't! And I don't even know what would be a good way to proceed --- apart from making explicit type declarations all the way up in my high-level code. Should I just change all the architecture?

Aucun commentaire:

Enregistrer un commentaire