Bizzare类型推理限制 - 多类型参数

时间:2015-08-19 13:43:02

标签: scala type-inference

为什么不编译?

trait Lol[A, SA] {
  def flatMap[B, SB](f: A => Lol[B, SB]): Lol[B, SB] = ???
}

val p1: Lol[Int, String] = ???
val p2: Lol[Double, Nothing] = ???

val p5 = p1.flatMap(_ => p2)

结果:

found   : Int => Lol[Double,Nothing]
required: Int => Lol[Double,SB]
   val p5 = p1.flatMap(_ => p2)
                         ^    

当开始编译时:

  • flatMap调用的类型参数是显式的
  • SA是协变的(wtf?)
  • Nothing中使用了p2以外的其他类型(例如Null
  • SBflatMap的返回类型中不会出现,或者出现在该返回类型的协变位置(例如,返回类型为Option[SB]

然而,上述解决方法对我来说是不可接受的。

2 个答案:

答案 0 :(得分:2)

为了更好地理解您的问题,可将其简化为:

class Lol[A]
def foo[B](f: Lol[B]) = f
foo(new Lol[Nothing])

,它会给你以下编译错误:

error: type mismatch;
 found   : Lol[Nothing]
 required: Lol[B]
Note: Nothing <: B, but class Lol is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)

一种可能的解决方案是更新代码片段:

def foo[B <: Lol[_]](f: B) = f

返回原始代码:

trait Lol[A, SA] {
  def flatMap[B <: Lol[_,_]](f: A => B): B = ???
}

答案 1 :(得分:2)

@ retronym对SI-9453的评论解释了你所看到的行为。这是一种解决方法......

我们可以合成一个等同于Nothing的类型,它不会导致typer收回推理解决方案,

type ReallyNothing = Nothing { type T = Unit }

即。 Nothing带有虚拟细化。现在以问题为例,

scala> :paste
// Entering paste mode (ctrl-D to finish)

trait Lol[A, SA] {
  def flatMap[B, SB](f: A => Lol[B, SB]): Lol[B, SB] = ???
}

val p1: Lol[Int, String] = ???
val p2: Lol[Double, ReallyNothing] = ???

val p5 = p1.flatMap(_ => p2)

// Exiting paste mode, now interpreting.

scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
  ... 37 elided