Лямбда-типы
Лямбда-тип позволяет выразить тип более высокого типа напрямую, без определения.
[X, Y] =>> Map[Y, X]
Например, приведенный выше тип определяет конструктор бинарного вида,
который сопоставляет аргументы X
и Y
с Map[Y, X]
.
Параметры типа лямбда-выражений могут иметь границы, но они не могут содержать аннотации вариантности +
или -
.
Пример:
type XY = [X, Y] =>> Map[Y, X]
val numbers: XY[String, Int] = Map(1 -> "first", 2 -> "second")
// numbers: Map[Int, String] = Map(1 -> "first", 2 -> "second")
numbers(1)
// res0: String = "first"
Проверка типа
Лямбда-тип, например, [X] =>> F[X]
определяет функцию от типов к типам.
Параметры могут иметь ограничения.
Если параметр ограничен, как [X >: L <: U] =>> F[X]
,
то проверяется, что аргументы параметров соответствуют границам L
и U
.
Только верхняя граница U
рассматривается включительно, т.е. что X
может в неё входить.
Правила подтипа
Рассмотрим два лямбда-выражения
type TL1 = [X >: L1 <: U1] =>> R1
type TL2 = [X >: L2 <: U2] =>> R2
Тогда TL1 <: TL2
, если
- интервал типов
L2 .. U2
содержится в интервале типаL1 .. U1
(т.е.L1 <: L2
иU2 <: U1
), R1 <: R2
Предполагается, что частично применяемый конструктор типа List
эквивалентен его Eta Expansion.
Т.е. List = [X] =>> List[X]
.
Это позволяет сравнивать конструкторы типов с лямбда-выражениями типов.
Связь с определениями параметризованного типа
Определение параметризованного типа
type T[X] = R
рассматривается как сокращение для непараметризованного определения с лямбда-типом в правой части:
type T = [X] =>> R
Если определение типа содержит аннотации вариантности +
или -
,
проверяется, удовлетворяет ли лямбда аннотации вариантности.
Например,
type F2[A, +B] = A => B
расширяется до
type F2 = [A, B] =>> A => B
и при этом проверяется, что параметр B
появляется ковариантно в A => B
.
Параметризованный абстрактный тип
type T[X] >: L <: U
считается сокращением для непараметризованного абстрактного типа с лямбда-выражениями типа в качестве границ.
type T >: ([X] =>> L) <: ([X] =>> U)
Однако, если L
- Nothing
, то он не параметризован, т.к. Nothing
считается нижним типом для всех видов.
Например,
type T[X] <: X => X
расширяется до
type T >: Nothing <: ([X] =>> X => X)
вместо
type T >: ([X] =>> Nothing) <: ([X] =>> X => X)
Те же расширения применяются к параметрам типа. Например,
[F[X] <: Coll[X]]
рассматривается как сокращение для
[F >: Nothing <: [X] =>> Coll[X]]
Абстрактные типы и псевдонимы непрозрачных типов запоминают вариантность, с которыми были созданы. Итак, тип
type F2[-A, +B]
известно, что он контравариантен в A
и ковариантен в B
и может быть реализован только с типами, которые удовлетворяют этим ограничениям.
Так же
opaque type O[X] = List[X]
O
известно, что оно инвариантно (а не ковариантно, как следует из его правой части).
С другой стороны, прозрачный псевдоним
type O2[X] = List[X]
будет рассматриваться как ковариантный, X
используется ковариантно в его правой части.
Каррированные параметры типа
Тело лямбда-типа может снова быть лямбда-типом. Пример:
type TL = [X] =>> [Y] =>> (X, Y)
Ссылки: