为什么会发生这种隐含的歧义行为?
Why is this implicit ambiguity behaviour happening?
我有一个类型类 Search
,如果我们有一个 TypeClass1[A]
或一个 TypeClass2[A]
实例,它就有一个实例 Search[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
,找到 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
和 case2
都满足条件。
在 scala 2.12.8 和 2.13.0 上观察到的行为
Scala 规范说:
If there are several eligible arguments which match the implicit parameter's type, a most specific one will be chosen using the rules of static overloading resolution.
https://www.scala-lang.org/files/archive/spec/2.13/07-implicits.html#implicit-parameters
The relative weight of an alternative A
over an alternative B
is a number from 0 to 2, defined as the sum of
- 1 if
A
is as specific as B
, 0 otherwise, and
- 1 if
A
is defined in a class or object which is derived from the class or object defining B
, 0 otherwise.
https://www.scala-lang.org/files/archive/spec/2.13/06-expressions.html#overloading-resolution
case1
是在一个对象中定义的,该对象是 派生的 来自 class (特征)定义 case2
但是反之亦然。
case2
与 case1
一样具体,但反之则不然。
所以 case1
相对 case2
的 相对权重 是 1+0=1 而 相对权重 case2
超过 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
}
我有一个类型类 Search
,如果我们有一个 TypeClass1[A]
或一个 TypeClass2[A]
实例,它就有一个实例 Search[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
,找到 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
和 case2
都满足条件。
在 scala 2.12.8 和 2.13.0 上观察到的行为
Scala 规范说:
If there are several eligible arguments which match the implicit parameter's type, a most specific one will be chosen using the rules of static overloading resolution.
https://www.scala-lang.org/files/archive/spec/2.13/07-implicits.html#implicit-parameters
The relative weight of an alternative
A
over an alternativeB
is a number from 0 to 2, defined as the sum of
- 1 if
A
is as specific asB
, 0 otherwise, and- 1 if
A
is defined in a class or object which is derived from the class or object definingB
, 0 otherwise.
https://www.scala-lang.org/files/archive/spec/2.13/06-expressions.html#overloading-resolution
case1
是在一个对象中定义的,该对象是 派生的 来自 class (特征)定义case2
但是反之亦然。case2
与case1
一样具体,但反之则不然。
所以 case1
相对 case2
的 相对权重 是 1+0=1 而 相对权重 case2
超过 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
}