Параметр типа ковариантности с несколькими ограничениями - PullRequest
2 голосов
/ 05 мая 2019

Я изучаю понятие дисперсии типов и границ в scala и как их использовать. Я сталкивался с вопросом о переполнении стека ниже, где одно из решений упоминало, как предотвратить обобщение типов в scala.

Параметр ковариантного типа

Ниже приведен код, размещенный в решении. В приведенном ниже коде как помогает добавление нового параметра типа C? Я понимаю, как ограничен B (как супертип A и подтип Fruit). Но я совершенно заблудился относительно того, что здесь делает С. Почему это должен быть супер тип A. Почему неявное доказательство требует, чтобы B был подтипом C?

И почему при добавлении объекта List of Orange возникает несущественная ошибка, что Fruit не является подтипом Banana. Может кто-нибудь объяснить это?

Я предполагаю, что для удовлетворения первого ограничения объект Orange обозначается как объект Fruit, но после этого теряется из-за того, что он говорит, что Fruit не является подтипом Banana.

case class Banana() extends Fruit
defined class Banana

case class Orange() extends Fruit
defined class Orange

case class Basket[+A <: Fruit](items: List[A]) {
    // ...
    def addAll[B >: A <: Fruit, C >: A](newItems: List[B])(implicit ev: B <:< C): Basket[B] =
  new Basket(items ++ newItems)
    // ...
  }
defined class Basket

val bananaBasket: Basket[Banana] = Basket(List(Banana(), Banana()))
bananaBasket: Basket[Banana] = Basket(List(Banana(), Banana()))

bananaBasket.addAll(List(Orange())) // not accepted
Main.scala:593: Cannot prove that Product with Serializable with cmd27.Fruit <:< cmd47.Banana.
bananaBasket.addAll(List(Orange()))

1 Ответ

2 голосов
/ 06 мая 2019

Синтаксис

def foo[A >: LA <: UA, B...](...)(implicit ev: F[A, B] <:< G[A, B], ...)

означает, что

  • во-первых A, B ... должно быть выведено так, чтобы выполнялись условия A >: LA <: UA, B... и
  • во-вторых для этих выводовA, B ... условия F[A, B] <:< G[A, B], ... должны быть проверены.

В основном C >: A и ev: B <:< C среднее (поскольку C больше нигде не используется, и компилятор ищет нижнюю верхнюю границу для C) что C равно A и для этого мы должны проверить, что B <:< A.Просто мы не можем удалить C >: A и заменить ev: B <:< C на ev: B <:< A с тех пор у нас будет Error: covariant type A occurs in contravariant position in type B <:< A of value ev.

Так что мы хотим, чтобы B был выведен так, чтобы B >: A <: Fruit (т.е.B должен быть супертипом из A) и для этого B проверить, что B <:< A (то есть B должно быть подтипом из A),Так что это может быть удовлетворено только тогда, когда A = B.И это предотвращает компиляцию bananaBasket.addAll(List(Orange())).

...