Enforcing precedence in implicit instances in Scala

只谈情不闲聊 提交于 2019-12-07 07:29:10

问题


This is a follow-up on the question Scala implicit typeclass precedence in companion objects.

Suppose that I have two traits, Trait2 extends Trait1. Each trait has a specific typeclass instance of Eq. I'd like to let the precedence of the typeclass instance of Trait2 to be higher than tha of Trait1. However, the code below (the LowPriorityImplicits trick) does not work.

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!

}

The following compilation error is thrown:

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)
   ^

How can I enforce the precedence relation of the typeclass instances?


回答1:


Variance in type parameters doesn't play well with Scala's encoding of type classes. If you want it to compile, simply try this.

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!

}

If you do want Eq[Trait2[A]] to behave like a sub-type of Eq[Trait1[A]], you might be able to use implicit conversions as a workaround.



来源:https://stackoverflow.com/questions/36996916/enforcing-precedence-in-implicit-instances-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!