Понимание аргументов типа не соответствует ошибке границ параметра типа класса при использовании параметра типа более высокого порядка - PullRequest
0 голосов
/ 09 мая 2020

Я пытаюсь понять, почему следующий фрагмент кода не компилируется, когда я использую параметр более высокого родства для T в MyModel

abstract class Model[M <: Model[M]]

class MyModel[T] extends Model[MyModel[T]]

class Bar[TModel <: Model[TModel]]

object Foo extends App {

  new Bar[MyModel[_]]

}

Но если я изменю его на new Bar[MyModel[Any]], он будет компилировать. Почему это?

1 Ответ

4 голосов
/ 09 мая 2020

Bar[MyModel[_]] равно Bar[MyModel[X] forSome {type X}].

(Его не следует путать ни с Bar[MyModel[X]] forSome {type X}, ни с Bar[MyModel[X forSome {type X}]], последнее просто Bar[MyModel[Any]]. Это три разных типа.)

Bar[MyModel[X] forSome {type X}] (он же Bar[MyModel[_]]) не компилируется, потому что MyModel[X] forSome {type X} (он же MyModel[_]) не удовлетворяет условию Bar TModel <: Model[TModel]. Действительно, вы можете проверить, что

implicitly[(MyModel[X] forSome {type X}) <:< Model[MyModel[X] forSome {type X}]]

не компилируется (X слева от <:< и X справа от <:< не связаны). Дело в , что сколемизация экзистенциального типа слева MyModel[X] forSome {type X}, а именно MyModel[X1] не связана с Model[MyModel[X] forSome {type X}] справа, для инварианта Model (от class MyModel[T] extends Model[MyModel[T]] следует, что MyModel[X1] <: Model[MyModel[X1]] (1), также MyModel[X1] <: (MyModel[X] forSome {type X}) (2), но для инварианта Model мы не можем применить Model к последнему «неравенству»).

Но если вы делаете Model ковариантным abstract class Model[+M <: Model[M]], тогда мы можем применить Model к «неравенству» (2), поэтому Model[MyModel[X1]] <: Model[MyModel[X] forSome {type X}] и это вместе с (1) дает MyModel[X1] <: Model[MyModel[X] forSome {type X}] по транзитивности. Итак, условие Bar выполнено, и new Bar[MyModel[_]] компилируется.

Bar[MyModel[Any]] компилируется, потому что MyModel[Any] удовлетворяет Bar условию TModel <: Model[TModel]. Действительно MyModel[Any] <: Model[MyModel[Any]], потому что class MyModel[T] extends Model[MyModel[T]] (вы можете проверить, что

implicitly[MyModel[Any] <:< Model[MyModel[Any]]]

компилируется).

...