我有一个叫Generator
:
trait Generator[A, B] {
def generate(in: Seq[A]): Seq[B]
}
我可以为此生成器提供Bind
实例:
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))
}
}
}
不幸的是,如果我尝试将我的生成器用作应用实例,那么类型推断就完全丢失了:
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)(_ / _)
我现在唯一的解决方法是为Generator
对象添加一个专门的方法:
def ^[T, A, B, C](g1: Generator[T, A], g2: Generator[T, B])(f: (A, B) => C) =
generatorBind[T].apply2(g1, g2)(f)
然后编译:
val g4 = Generator.^(g1, g2)(_ / _)
这个问题有解决方法吗?我想是因为使用State[S, A]
作为Monad
会产生同样的问题(但在Scalaz中似乎对State
有特殊处理。)
答案 0 :(得分:2)
如果明确注释g1
和g2
类型,则可以使用ApplicativeBuilder,或更改为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)(_ / _)
答案 1 :(得分:0)
我认为隐式宏fundep materialization(又称函数依赖)是为了帮助它。
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))
它需要宏观天堂。