为什么会发生这种隐含的歧义行为?

2024-03-05

我有一个类型类Search,其中有一个实例Search[A]如果我们有一个TypeClass1[A] or a TypeClass2[A]实例。优先考虑1实例。

编译如下:

trait TypeClass1[A]
trait TypeClass2[A]
trait Search[A]

object Search extends LPSearch {
  implicit def case1[A](implicit ev: TypeClass1[A]): Search[A] = null
}

trait LPSearch {
  implicit def case2[A](implicit ev: TypeClass2[A]): Search[A] = null
}

object Test {
  implicit val ev1: TypeClass1[Int] = null
  implicit val ev2: TypeClass2[Int] = null
  implicitly[Search[Int]]
}

这正如我所期望的,隐式搜索发现case1, finds ev1,并停止搜索。

然而,如果我们改变TypeClass2为了获得更多结构,隐式搜索停止工作:

trait TypeClass1[A]
trait TypeClass2[M[_], A]
trait Search[A]

object Search extends LPSearch {
  // This is the same as before
  implicit def case1[A](implicit ev: TypeClass1[A]): Search[A] = null
}

trait LPSearch {
  implicit def case2[M[_], A](implicit ev: TypeClass2[M, A]): Search[M[A]] = null
}

object Test {
  implicit val ev1: TypeClass1[List[Int]] = null
  implicit val ev2: TypeClass2[List, Int] = null

  // Does not compile:
  implicitly[Search[List[Int]]]
}

为什么上面的例子中最后一行不能编译?

它失败了ambiguous implicit values,说两者case1 and case2满足条件。

在 scala 2.12.8 和 2.13.0 上观察到的行为


Scala 规范说:

如果有多个符合隐式参数类型的参数,则将使用静态重载解析规则选择最具体的一个。

https://www.scala-lang.org/files/archive/spec/2.13/07-implicits.html#implicit-parameters https://www.scala-lang.org/files/archive/spec/2.13/07-implicits.html#implicit-parameters

替代方案的相对权重A超过替代方案B是一个从 0 到 2 的数字,定义为

  • 1 if A具体如下B,否则为 0,并且
  • 1 if A是在类或对象中定义的,该类或对象派生自定义的类或对象B, 否则为 0。

https://www.scala-lang.org/files/archive/spec/2.13/06-expressions.html#overloading-resolution https://www.scala-lang.org/files/archive/spec/2.13/06-expressions.html#overloading-resolution

  • case1被定义在一个对象中,该对象是derived从类(特质)定义case2但反之则不然。

  • case2 is 具体如 case1但反之则不然。

So 相对重量 of case1 over case21+0=1 且相对重量 of case2 over case1是0+1=1。所以这就是歧义。

Error: ambiguous implicit values:
 both method case2 in trait LPSearch of type [M[_], A](implicit ev: App.TypeClass2[M,A])App.Search[M[A]]
 and method case1 in object Search of type [A](implicit ev: App.TypeClass1[A])App.Search[A]
 match expected type App.Search[List[Int]]
    implicitly[Search[List[Int]]]

在第二种情况下,使用低优先级特征是没有意义的,因为如果两个隐式都匹配预期类型,case2当它们被定义在同一个对象中时是首选。所以尝试一下

object Search {
  implicit def case1[A](implicit ev: TypeClass1[A]): Search[A] = null
  implicit def case2[M[_], A](implicit ev: TypeClass2[M, A]): Search[M[A]] = null
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么会发生这种隐含的歧义行为? 的相关文章

随机推荐