Scala Система неявных приоритетов - PullRequest
2 голосов
/ 25 марта 2020

У меня есть вопрос, связанный с системой неявных приоритетов. У меня есть следующий код:

object MyMain extends App {
  case class Plain(s: String)
  // cats version
  trait CatShow[T] extends ContravariantShow[T]

  object CatShow {
    def apply[A](implicit instance: CatShow[A]): CatShow[A] = instance

    trait ContravariantShow[-T] extends Serializable {
      def show(t: T): String
    }

    def show[A](f: A => String): CatShow[A] = new CatShow[A] {
      def show(a: A): String = f(a)
    }
  }
  // my simplified version
  trait MyShow[-T] extends Serializable {
    def show(t: T): String
  }

  object MyShow {
    def apply[A](implicit instance: MyShow[A]): MyShow[A] = instance

    def show[A](f: A => String): MyShow[A] = new MyShow[A] {
      def show(a: A): String = f(a)
    }
  }
  // implicits definition for both
  abstract class ImplicitInstances0 extends ImplicitInstances1 {
    implicit val catShowPlain: CatShow[Plain] = CatShow(_.toString + "[cat-plain]")
    implicit val myShowPlain: MyShow[Plain] = MyShow(_.toString + "[my-plain]")
  }

  abstract class ImplicitInstances1 {
    implicit val catShowAny: CatShow[Any] = CatShow(_.toString + "[cat-Any]")
    implicit val myShowAny: MyShow[Any] = MyShow(_.toString + "[my-Any]")
  }

  object ImplicitInstances extends ImplicitInstances0

  import ImplicitInstances._

  implicitly[CatShow[Plain]] // works magically
  implicitly[MyShow[Plain]] // [ERROR] compiler error for ambiguous implicit 

}

просто интересно, почему ContravariantShow поможет компилятору для расстановки приоритетов. В идеале я хотел бы go через 2 случая шаг за шагом показать, почему один работает, а другой не работает.

Спасибо

1 Ответ

4 голосов
/ 25 марта 2020

просто интересно, почему ContravariantShow поможет компилятору при расстановке приоритетов.

ContravariantShow не поможет приоритизации. Если вы удалите его, неявное все равно разрешит.

trait CatShow[T] /*extends ContravariantShow[T]*/ {
  def show(t: T): String // added
}

object CatShow {
  def apply[A](implicit instance: CatShow[A]): CatShow[A] = instance

//  trait ContravariantShow[-T] extends Serializable {
//    def show(t: T): String
//  }

  def show[A](f: A => String): CatShow[A] = new CatShow[A] {
    def show(a: A): String = f(a)
  }
}

Что важно, так это дисперсия класса типов. CatShow инвариантен, а MyShow контравариантен. Когда вы ищете implicitly[CatShow[Plain]] только catShowPlain является кандидатом. Когда вы ищете implicitly[MyShow[Plain]], оба myShowAny (потому что implicitly[MyShow[Any] <:< MyShow[Plain]]) и myShowPlain являются кандидатами. И они делают двусмысленность из-за причины Почему происходит это неявное поведение двусмысленности?

...