#scala #generics #wildcard #existential-type #higher-kinded-types
#scala #общие #подстановочный знак #existential-type #типы более высокого типа
Вопрос:
Интересно, почему работает следующее (обратите внимание, что функтор или аппликатив не имеют значения для примера)
trait Functor[F[_]]
trait Applicative[F[_]] extends Functor[F]
Но не
trait Functor[F[_]]
trait Applicative[F[_]] extends Functor[F[_]]
Моя проблема связана с F vs F[_]
Какое здесь правило?
Особенно компилятор выдает критическую ошибку:
F[_] не принимает параметров типа, ожидается: один
Комментарии:
1. Вас смущают синтаксисы для экзистенциальных типов и типов более высокого типа?
Ответ №1:
Подчеркивание ( _
) имеет разное значение на сайте определения (1) и на сайте вызова (2).
(1) На сайте определения подчеркивание означает, что универсальный (параметр типа) является конструктором типа ( * => *
), а не надлежащим типом ( *
).
trait A[X] // X is a proper type, *
// ^^^ definition
trait B[X] extends A[X] // X is a proper type, *
// ^^^ definition, ^^^ call
trait A[F[_]] // F is a type constructor, * => *
// ^^^^ definition
trait B[F[_]] extends A[F] // F is a type constructor, * => *
// ^^^^ definition, ^^^ call
Поскольку на сайте определения уже один раз подчеркнуто, что F
это конструктор типа, на сайте вызова он всегда упоминается как просто F
(нет необходимости в дополнительном, _
если вы имеете в виду конструктор того же типа F
).
(2) На сайте вызова для конструктора типа ( * => *
) F
F[_]
означает экзистенциальный тип. Существующий тип — это правильный тип ( *
).
trait A[X] // X is a proper type, *
// ^^^ definition
trait B[F[_]] // F is a type constructor, * => *
extends A[F[_]] // F[_] is an existential type, *
// ^^^^ definition, ^^^^ call
Комментарии:
1. Глупый вопрос, но каково было бы правильное определение сайта вызова для типа. Я понял, что вы написали выше, но могу обобщить, что в моей голове делает сайт вызова, сайт вызова. Это только в случае расширений?
2. @MaatDeamon Я имел в виду везде, где вы ссылаетесь на тип (за исключением случаев, когда он определен).
extends A[X]
,type T = X
,foo[X]()
Bar[X]
и т.д.
Ответ №2:
trait Functor[F[_]]
означает, что для функтора требуется конструктор типа (тип с отверстием, который создает новый тип, когда отверстие заполнено).
Тогда, trait Applicative[F[_]] extends Functor[F]
здесь вы говорите, что для Applicative также требуется что-то с одним отверстием. Таким образом, F
уже понимается как нечто с одним отверстием, и поэтому передача его функтору имеет смысл.
Наконец, здесь extends Functor[F[_]]
то же самое, что и extends Functor[F[T] forSome { type T } ]
, поэтому вы заполняете пробел F
, и, следовательно, он больше не применим к функтору.
Ответ №3:
В Scala 3.2 существует план (Dotty) сделать F[_]
значение одинаковым как на сайте определения, так и на сайте вызова
В Scala 3.2 значение _ меняется с подстановочного знака на заполнитель для параметра типа.
таким образом, допустимым синтаксисом станет следующее
trait Applicative[F[_]] extends Functor[F[_]] // Both F[_] represent type lambda [X] =>> F[X]
Цель состоит в том, чтобы заменить подстановочный знак (экзистенциальный) тип F[_]
на F[?]
. Это уже видно в Dotty REPL
Starting dotty REPL...
scala> val l: List[_] = List(42)
val l: List[?] = List(42)
и если скомпилировано с source:3.1 -deprecation
, предупреждение уже поднято
dotc -source:3.1 -deprecation Main.scala
-- Deprecation Warning: Main.scala:2:14 ----------------------------------------
2 | val l: List[_] = List(42)
| ^
| `_` is deprecated for wildcard arguments of types: use `?` instead
1 warning found
Для этой цели kind-projector превентивно изменил свой синтаксис type lambda с F[?]
на F[*]
, чтобы освободить место ?
для существующего типа Scala 3.
В качестве дополнительного примечания рассмотрим, как вид конструктора типа может быть выражен в настоящее время в Dotty
Starting dotty REPL...
scala> trait Functor[F <: [X] =>> Any]
| trait Applicative[F <: [X] =>> Any] extends Functor[F]
// defined trait Functor
// defined trait Applicative
scala> trait Applicative[F <: [X] =>> Any] extends Functor[[X] =>> F[X]]
// defined trait Applicative
Вид [X] =>> Any
является синтаксическим подобием неформальной нотации, * => *
упомянутой Дмитрием выше.