Лямбда-типы

Лямбда-тип позволяет выразить тип более высокого типа напрямую, без определения.

[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, если

Предполагается, что частично применяемый конструктор типа 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)

Ссылки: