4

我有一个 typeclass ,如果我们有一个或一个实例Search,它就有一个实例。优先考虑实例。Search[A]TypeClass1[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]]
}

正如我所期望的那样,隐式搜索 finds case1, findsev1并停止搜索。

但是,如果我们更改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,说两者case1case2满足条件。

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

4

1 回答 1

6

Scala规范说:

如果有几个符合条件的参数与隐式参数的类型匹配,则将使用静态重载决策规则选择最具体的参数。

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

A一个备选方案相对于一个备选方案的相对权重B是一个从 0 到 2 的数字,定义为

  • 如果A与 一样具体B,则为 1,否则为 0,并且
  • 如果A在从定义的类或对象派生的类或对象中定义B,则为 1,否则为 0。

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

  • case1在从定义的类(特征)派生的对象中定义,case2反之亦然。

  • case2一样的具体, case1但反之则不然。

所以over的相对权重是1+0=1 ,over的相对权重是0+1=1。所以是模棱两可的。case1case2case2case1

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
}
于 2019-09-14T09:59:28.807 回答