Ges*_*sar 3 scala implicit typeclass ambiguous type-level-computation
我有一个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]]
}
Run Code Online (Sandbox Code Playgroud)
就像我期望的那样,隐式搜索finds 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]]]
}
Run Code Online (Sandbox Code Playgroud)
为什么在上面的示例中最后一行没有编译?
都失败ambiguous implicit values,说case1并case2满足条件。
在Scala 2.12.8和2.13.0上观察到的行为
Scala规范说:
如果有多个与隐式参数的类型匹配的合格参数,则将使用静态重载解析规则选择一个最具体的参数。
https://www.scala-lang.org/files/archive/spec/2.13/07-implicits.html#implicit-parameters
一种替代的相对重量
A比的替代B是从0到2的数,定义为的总和
- 如果
A与1 一样具体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但并非如此)一样具体。
所以相对重量的case1超过case2为1 + 0 = 1和相对重量的case2超过case10 + 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]]]
Run Code Online (Sandbox Code Playgroud)
在第二种情况下,使用低优先级特征是没有意义的,因为如果两个隐式都匹配期望的类型,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
}
Run Code Online (Sandbox Code Playgroud)