Thursday, 19 September 2013

How to help Scalaz with type inference and 2 type parameters

How to help Scalaz with type inference and 2 type parameters

I have something called a Generator:
trait Generator[A, B] { def generate(in: Seq[A]): Seq[B] }
I can provide a Bind instance for this generator:
object Generator {
implicit def generatorBind[T]: Bind[({type l[B] = Generator[T, B]})#l] =
new Bind[({type l[B] = Generator[T, B]})#l] {
def map[A, B](generator: Generator[T, A])(f: A => B): Generator[T, B]
= new Generator[T, B] {
def generate(in: Seq[T]): Seq[B] = generator.generate(in).map(f)
}
def bind[A, B](generator: Generator[T, A])(f: A =>Generator[T, B]):
Generator[T, B] = new Generator[T, B] {
def generate(in: Seq[T]): Seq[B] = generator.generate(in).flatMap(v
=> f(v).generate(in))
}
}
}
Unfortunately, type inference is completely lost if I try to use my
generators as applicative instances:
val g1 = new Generator[Int, Int] { def generate(seq: Seq[Int]) = seq.map(_
+ 1) }
val g2 = new Generator[Int, Int] { def generate(seq: Seq[Int]) = seq.map(_
+ 10) }
// doesn't compile
// can make it compile with ugly type annotations
val g3 = ^(g1, g2)(_ / _)
My only workaround for now has been to add a specialised method to the
Generator object:
def ^[T, A, B, C](g1: Generator[T, A], g2: Generator[T, B])(f: (A, B) => C) =
generatorBind[T].apply2(g1, g2)(f)
Then this compiles:
val g4 = Generator.^(g1, g2)(_ / _)
Is there a workaround for this problem? I suppose there is because using
State[S, A] as a Monad poses the same kind of issue (but in Scalaz there
seems to be a special treatment for State).

No comments:

Post a Comment