Переопределение дисперсии в подтипе

Может кто-нибудь объяснить мне, почему пример 1 компилируется, но пример 2 не работает?

Пример 1:

trait Foo[+A]
trait Bar[A] extends Foo[A]

Пример 2:

trait Foo[A[+_]]
trait Bar[A[_]] extends Foo[A]

Пример 2 не компилируется со следующим сообщением об ошибке: "Типы аргументов типа (A) не соответствуют ожидаемым типам параметров типа (тип A) в признаке Foo. Параметры типа не соответствуют типу A ожидаемые параметры: тип _ (в  trait Bar) является инвариантным, но тип _ (в признаке Foo) объявляется ковариантным "

Ответ 1

В примере 1 +A не является ограничением на A. Любой тип может быть параметром Foo. Это ограничение на Foo. Это означает, что в интерфейсе Foo, A может появляться только в ковариантной позиции (в скором времени это может быть результат метода, но не параметр метода).

Наличие Bar не ковариантного означает, что интерфейс Bar не удовлетворяет одному и тому же ограничению (или, по крайней мере, не рекламирует его), поэтому, возможно, в Bar был добавлен метод с параметром A. Это довольно часто. Например, существует collection.Seq[+A], и оно расширяется на collection.mutable.Seq[A]. Это не создает проблем. Если Y <: X, a Bar[Y] не является Bar[X], но все равно a Foo[X].

С другой стороны, в примере 2 A[+_] является ограничением на A. Только типы с параметром ковариантного типа могут быть параметрами Foo. Код Foo, вероятно, использует это ограничение, например назначение A[String] в A[Any] где-то в коде Foo.

Тогда разрешение Bar на создание нековариантного типа было бы необоснованным. Код, унаследованный от Foo, все еще можно вызвать и присвоить A[String] A[Any], когда A больше не ковариантно.

Очень похожая проблема со звуком будет возникать в любое время, когда вы позволите снять ограничение на общий параметр. Предположим, что у вас есть Foo[X <: Ordered[X]] (или Foo[X : ordering]), и у вас есть метод sort в Foo. Предположим, что Bar[X] extends Foo разрешено. Возможно, ничто в коде Bar не требует X для упорядочивания, но тем не менее sort будет вызываемым, и, несомненно, будет неверно работать с элементами, которые нельзя упорядочить.


Относительно вашего вопроса в комментарии с помощью Traversable [+ Elem, + Col [+ _]] и расширения этого в make mutable class:

технически, да, вы можете расширить его и поместить в него var youCanMutateThat : Elem = _. Наверное, это не то, что вы ищете. Но я предполагаю, что ваш план позволит использовать расширение с изменчивым Col, и я не думаю, что вы можете это сделать по указанной выше причине. Но почему, почему у вас есть ограничение Col [+ _] в первую очередь?

Ответ 2

В примере 2 нужно добавить covarince для A [_]

trait Bar[A[+_]] extends Foo[A]

Поскольку Foo ожидает, что ковариантный тип в качестве параметра (+ _ является частью ограничения для замещенного типа), а унаследованный тип требует, чтобы этот параметр был ковариантным (ограничение замещенного типа).

В примере 1 вы определяете, что Foo (например, контейнер) ковариантно по параметру, и унаследованный контейнер может быть инвариантным (без ограничений для замещенного типа)

более подробно в теории типа Мартина-Лёфа (предикативный параметрический полиморфизм)