为什么在没有子类型证据的情况下,这个多功能案例的隐式推导失败了



下面的例子中有两个类似的无形状多态函数。它们之间唯一的区别是deserSucceeding的隐式案例定义有一个额外的证据(implicit e: FS <: FromStr[T])的亚型。Scala未能为deserFailing派生隐式Aux.Case,但为deserSucceeding派生成功。

为什么?这是scala编译器的限制吗?还是deserSucceeding会导致隐式推导/类型推理中的歧义?

import shapeless._
type FromStr[T] = String => T
object FromDouble extends FromStr[Double] {
override def apply(v1: String): Double = v1.toDouble
}
object deserFailing extends Poly2 {
implicit def kase[T, FS <: FromStr[T]]: Case.Aux[String, FS, T] = at((s, fs) => fs(s))
}
// fails to derive a `Case.Aux`
deserFailing("1.0", FromDouble)
object deserSucceeding extends Poly2 {
implicit def kase[T, FS](implicit e: FS <:< FromStr[T]): Case.Aux[String, FS, T] = at((s, fs) => fs(s))
}
deserSucceeding("1.0", FromDouble)

TL;DR;是类型推理的工作方式。

当执行[T, FS <: FromStr[T]]时,编译器会尝试在同一类型下推断两者,因此可能最终会从其中一个类型中推断出AnyNothing,以检查子类型对类型的约束
而第二个选项在推理过程中不强制任何子类型限制,这使编译器能够推断出更好的类型,然后检查子类型约束。

它类似于这个例子:

def tupleIfSubtype1[T <: U, U](t: T, u: U) = (t, u)
def tupleIfSubtype2[T, U](t: T, u: U)(implicit ev: T <:< U) = (t, u)
tupleIfSubtype1("Foo", 3) // compiles, it infers Any for the second element.
tupleIfSubtype2("Foo", 3) // doesn't compile.

更深入的解释,在这里。

最新更新