Ковариация в Scala

Я изучаю Принципы функционального программирования в Scala, когда читал лекцию Подтипы и обобщения, у меня возникла путаница по поводу ковариации:

Дано: NonEmpty <: IntSet или NonEmpty является подтипом IntSet

Является ли List[NonEmpty] <: List[IntSet] или List[NonEmpty] подтипом List[IntSet]?

И ответ таков: список непустых множеств - это частный случай списка произвольных множеств.

Означает ли этот ответ, что List[NonEmpty] является подтипом List[IntSet]?

Итак, я попробовал это:

val nonEmpty: List[NonEmpty] = null
val intSet: List[IntSet] = nonEmpty 

Затем у меня возникла ошибка компиляции:

Выражение типа List [NonEmpty] не соответствует ожидаемому типу List [IntSet]

Насколько я знаю, дженерики инвариантны в Java, ковариантны ли дженерики в Scala, или я неправильно понимаю согласованность?

Редактировать:

Вот определения IntSet, NonEmpty, List:

abstract class IntSet {
  def contains(x: Int): Boolean
  def incl(x: Int): IntSet
  def union(other: IntSet): IntSet
}

class NonEmpty(elem: Int, left: IntSet, right: IntSet) extends IntSet {...}

trait List[T] {
  def isEmpty: Boolean
  def head: T
  def tail: List[T]
}

person toandv    schedule 15.06.2016    source источник
comment
Он должен скомпилироваться (при условии, что вы используете стандартный Scala List). Какие определения для NonEmpty и IntSet?   -  person Alexey Romanov    schedule 15.06.2016
comment
@AlexeyRomanov: Я перехожу на Scala List, и он соответствует, но я не понимаю, почему, разве они оба не являются универсальными типами.   -  person toandv    schedule 15.06.2016
comment
scala.collection.immutable.List[+A] ковариантен на A, что обозначено символом +.   -  person J Cracknell    schedule 15.06.2016


Ответы (2)


Проблема в вашем определении List; его параметр типа не имеет префикса +, чтобы указать, что параметр типа является ковариантным. Измените его на это:

trait List[+T] {
  def isEmpty: Boolean
  def head: T
  def tail: List[T]
}
person oxbow_lakes    schedule 15.06.2016

Во-первых, вы должны знать, что

В Scala, однако, универсальные типы по умолчанию имеют nonvariant (или «жесткий») подтип.

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

если S является подтипом типа T, то следует считать List [S] подтипом List [T]

nonvariant имеет другое значение:

если S является подтипом типа T, тогда List [S] не должен считаться подтипом List [T]

Вам поможет документ. Просто выполните поиск по слову covariance, и вы найдете ответ на свой вопрос.

Удачи

person Jerry    schedule 15.06.2016