简体   繁体   English

如何使用类型推断和2个类型参数帮助Scalaz

[英]How to help Scalaz with type inference and 2 type parameters

I have something called a Generator : 我有一个叫做Generator东西:

trait Generator[A, B] {
  def generate(in: Seq[A]): Seq[B]
}

I can provide a Bind instance for this generator: 我可以为此生成器提供一个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))
    }
  }
}

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: 我目前唯一的解决方法是向Generator对象添加专门的方法:

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 ). 我想是因为将State[S, A]用作Monad引起同样的问题(但在Scalaz中似乎对State有特殊的处理)。

You can use ApplicativeBuilder if explicitly annotate g1 and g2 types, or change to abstract class Generator 如果显式注释g1g2类型,则可以使用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)(_ / _)

I think implicit macro's fundep materialization (aka functional dependency) is to help this. 我认为隐式宏的Fundep实现 (也称为功能依赖)可以帮助实现这一点。

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

It requires macro paradise tho. 它需要宏的天堂。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM