在Scala中的隐式实例中强制执行优先级



这是对伴随对象中Scala隐式类型类优先级问题的后续研究。

假设我有两个特征,Trait2 extends Trait1。每个特征都有一个Eq的特定类型类实例。我想让Trait2的typeclass实例的优先级高于Trait1的优先级。但是,下面的代码(LowPriorityImplicits技巧)不起作用。

trait Eq[-A] {
  def eq(a: A, b: A): Boolean
}
object Eq {
  implicit object IntEq extends Eq[Int] {
    def eq(a: Int, b: Int) = a == b
  }
}
trait Trait1[+A]
trait Trait2[+A] extends Trait1[A]
object Implicits extends LowPriorityImplicits {
  implicit def Eq2[T: Eq]: Eq[Trait2[T]] = ???
}
trait LowPriorityImplicits {
  implicit def Eq1[T: Eq]: Eq[Trait1[T]] = ???
}
object Test2 extends App {
  def f[T: Eq](x: T) = ???
  import Implicits._
  val t1 = new Trait1[Int] {}
  val t2 = new Trait2[Int] {}
  f(t2) // COMPILATION ERROR!
}

引发以下编译错误:

Error:(33, 4) ambiguous implicit values:
 both method Eq1 in trait LowPriorityImplicits of type [T](implicit evidence$2: Eq[T])Eq[Trait1[T]]
 and method Eq2 in object Implicits of type [T](implicit evidence$1: Eq[T])Eq[Trait2[T]]
 match expected type Eq[Trait2[Int]]
  f(t2)
   ^

如何强制类型类实例的优先级关系?

类型参数的方差在Scala对类型类的编码中不起作用。如果你想编译它,只需尝试一下。

trait Eq[A] {
  def eq(a: A, b: A): Boolean
}
object Eq {
  implicit object IntEq extends Eq[Int] {
    def eq(a: Int, b: Int) = a == b
  }
}
trait Trait1[A]
trait Trait2[A] extends Trait1[A]
object Implicits extends LowPriorityImplicits {
  implicit def Eq2[T: Eq]: Eq[Trait2[T]] = ???
}
trait LowPriorityImplicits {
  implicit def Eq1[T: Eq]: Eq[Trait1[T]] = ???
}
object Test2 extends App {
  def f[T: Eq](x: T) = ???
  import Implicits._
  val t1 = new Trait1[Int] {}
  val t2 = new Trait2[Int] {}
  f(t2) // COMPILATION ERROR!
}

如果确实希望Eq[Trait2[A]]的行为类似于Eq[Trait1[A]]的子类型,则可以使用隐式转换作为解决方法。

最新更新