微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么在没有子类型证据的情况下,这个多函数案例的隐式推导会失败?

如何解决为什么在没有子类型证据的情况下,这个多函数案例的隐式推导会失败?

在下面的例子中有两个相似的无形多态函数。它们之间的唯一区别是 deserSucceeding 的隐式 case 定义有一个额外的子类型证据 (implicit e: FS <: FromStr[T])。 Scala 无法为 Aux.Case 导出隐式 deserFailing,但为 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) => 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: U)(implicit ev: T <:< U) = (t,u)

tupleIfSubtype1("Foo",3) // compiles,it infers Any for the second element.
tupleIfSubtype2("Foo",3) // doesn't compile.

更深入的解释,here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。