How to help Scalaz with output type and 2 types of parameters

I have something called 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 now was to add a specialized 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 it compiles:

 val g4 = Generator.^(g1, g2)(_ / _) 

Is there a workaround for this problem? I believe this is due to the fact that using State[S, A] as Monad poses the same question (but in Scalaz, there seems to be a special treatment for State ).

+4
source share
2 answers

You can use ApplicativeBuilder if you explicitly annotate the types g1 and g2 , or change to an abstract class Generator

 // java.lang.Object with Generator[Int, Int] !!! val badInference = new Generator[Int, Int] { def generate(seq: Seq[Int]) = seq.map(_ + 1) } val g1: Generator[Int, Int] = new Generator[Int, Int] { def generate(seq: Seq[Int]) = seq.map(_ + 1) } val g2: Generator[Int, Int] = new Generator[Int, Int] { def generate(seq: Seq[Int]) = seq.map(_ + 10) } val g3 = (g1 |@| g2)(_ / _) 
+2
source

I think that the implicit macro fundep materialization (aka functional dependency) helps.

 trait Iso[T, U] { def to(t: T) : U def from(u: U) : T } case class Foo(i: Int, s: String, b: Boolean) def conv[C](c: C)(implicit iso: Iso[C, L]): L = iso.from(c) val tp = conv(Foo(23, "foo", true)) 

This requires macro paradise.

0
source

All Articles