Что такое более высокий тип в Scala?


275

Вы можете найти следующее в Интернете:

  1. Тип с более высоким родом == Конструктор типа?

    class AClass[T]{...} // For example, class List[T]

    Некоторые говорят, что это тип с более высоким родом, потому что он абстрагируется от типов, которые будут соответствовать определению.

    Типы с более высоким родом - это типы, которые принимают другие типы и создают новый тип.

    Они также известны как конструктор типов . (Например, в Программирование в Scala ).

  2. Тип с более высоким родом == конструктор типа, который принимает конструктор типа в качестве параметра типа?

    В статье « Генерика высшего рода» вы можете прочитать

    ... типы, которые абстрагируются над типами, которые абстрагируются над типами («типы с более высоким родом») ... "

    что говорит о том, что

    class XClass[M[T]]{...} // or
    
    trait YTrait[N[_]]{...} // e.g. trait Functor[F[_]]

    является более родственным типом.

Таким образом, учитывая это, трудно различить конструктор типа , тип с более высоким родом и конструктор типа, который принимает конструкторы типа в качестве параметра типа , поэтому вопрос выше.


Добавлен Фанктор Ландеи в качестве примера.
Лутц

Ответы:


284

Позвольте мне восполнить некоторые из этих недоразумений, объясняя это неоднозначностью. Мне нравится использовать аналогию с уровнем стоимости, чтобы объяснить это, поскольку люди, как правило, лучше знакомы с ней.

Конструктор типа - это тип, который можно применять к аргументам типа для «конструирования» типа.

Конструктор значения - это значение, которое можно применить к аргументам значения, чтобы «создать» значение.

Конструкторы значений обычно называются «функциями» или «методами». Эти «конструкторы» также называются «полиморфными» (потому что они могут использоваться для конструирования «вещей» различной «формы») или «абстракций» (поскольку они абстрагируются от того, что варьируется между различными полиморфными экземплярами).

В контексте абстракции / полиморфизма первый порядок относится к «одноразовому использованию» абстракции: вы абстрагируетесь над типом один раз, но сам этот тип не может абстрагироваться над чем-либо. Java 5 дженерики первого порядка.

Интерпретация первого порядка вышеуказанных характеристик абстракций:

Конструктор типа - это тип, который можно применить к подходящим аргументам типа, чтобы «создать» правильный тип.

Конструктор значения - это значение, которое можно применить к аргументам правильного значения, чтобы «создать» правильное значение.

Подчеркнем, что здесь нет абстракции (я думаю, вы могли бы назвать это «нулевым порядком», но я нигде не видел, чтобы это использовалось), например, значение 1или тип String, мы обычно говорим, что это «правильное» значение или тип.

Подходящее значение «сразу же можно использовать» в том смысле, что оно не ожидает аргументов (оно не абстрагируется от них). Думайте о них как о значениях, которые вы можете легко распечатать / проверить (сериализация функции обманывает!).

Правильный тип - это тип, который классифицирует значения (включая конструкторы значений), конструкторы типов не классифицируют никакие значения (их сначала нужно применить к аргументам правильного типа, чтобы получить правильный тип). Для создания экземпляра типа необходимо (но не достаточно), чтобы это был правильный тип. (Это может быть абстрактный класс или класс, к которому у вас нет доступа.)

«Высший порядок» - это просто общий термин, который означает многократное использование полиморфизма / абстракции. Это означает то же самое для полиморфных типов и значений. Конкретно, абстракция высшего порядка абстрагируется от чего-то, что абстрагируется от чего-то. Для типов термин «более высокий род» является специализированной версией более общего «высшего порядка».

Таким образом, версия нашей характеристики высшего порядка становится:

Конструктор типа - это тип, который можно применять к аргументам типа (правильные типы или конструкторы типов) для «конструирования» правильного типа (конструктора).

Конструктор значения - это значение, которое можно применить к аргументам значения (правильные значения или конструкторы значений), чтобы «построить» правильное значение (конструктор).

Таким образом, «высший порядок» просто означает, что когда вы говорите «абстрагируясь над X», вы действительно это имеете в виду! X, Что абстрагируется над не теряет свое «право абстракции»: оно может абстрагироваться от все она хочет. (Между прочим, я использую здесь глагол «абстрактный», чтобы означать: опустить что-то, что не является существенным для определения значения или типа, так что оно может быть изменено / предоставлено пользователем абстракции в качестве аргумента .)

Вот несколько примеров (вдохновленных вопросами Лутца по электронной почте) правильных значений и типов первого и высшего порядка:

                   proper    first-order           higher-order

values             10        (x: Int) => x         (f: (Int => Int)) => f(10)
types (classes)    String    List                  Functor
types              String    ({type λ[x] = x})#λ   ({type λ[F[x]] = F[String]})#λ

Где используемые классы были определены как:

class String
class List[T]
class Functor[F[_]]

Чтобы избежать косвенного определения классов, вам нужно как-то выразить функции анонимного типа, которые не могут быть выражены напрямую в Scala, но вы можете использовать структурные типы без слишком больших синтаксических издержек ( -style из-за https://stackoverflow.com). / users / 160378 / retronym afaik):

В некоторой гипотетической будущей версии Scala, которая поддерживает функции анонимного типа, вы можете сократить эту последнюю строку из примеров до:

types (informally) String    [x] => x              [F[x]] => F[String]) // I repeat, this is not valid Scala, and might never be

(Лично я сожалею, что когда-либо говорил о «типах с более высоким родом», в конце концов, это просто типы! Когда вам абсолютно необходимо устранить неоднозначность, я предлагаю сказать такие вещи, как «параметр конструктора типа», «член конструктора типа»). или «псевдоним конструктора типов», чтобы подчеркнуть, что речь идет не только о правильных типах.)

PS: чтобы еще больше усложнить ситуацию, «полиморфный» неоднозначен по-другому, так как полиморфный тип иногда означает универсально квантифицированный тип, такой как Forall T, T => T, который является правильным типом, поскольку он классифицирует полиморфные значения (в Scala это значение может быть записывается как структурный тип {def apply[T](x: T): T = x})



5
Статья Адриана «Полиморфизм конструкторов типов» теперь на adriaanm.github.com/research/2010/10/06/…
Стивен Шоу

Я продолжаю читать это как более родственный и воображающий родственный дух
Янак Мина

110

(Этот ответ является попыткой украсить ответ адрианских мавров некоторой графической и исторической информацией.)

Более старшие виды являются частью Scala с 2.5.

  • До этого Scala, как и Java до сих пор, не разрешал использовать конструктор типов («generics» в Java) для использования в качестве параметра типа для конструктора типов. например

     trait Monad [M[_]]

    не представилось возможным.

    В Scala 2.5 система типов была расширена за счет возможности классифицировать типы на более высоком уровне (известный как полиморфизм конструктора типов ). Эти классификации известны как виды.

    Тип и вид реализации, ** полученный ** из "Дженерики высшего рода" (Изображение получено из Дженерики высшего сорта )

    Следствием этого является то, что конструктор типов (например List) может использоваться так же, как и другие типы в позиции параметра типа конструкторов типов, и поэтому они стали первоклассными типами начиная с Scala 2.5. (Подобно функциям, которые являются первоклассными значениями в Scala).

    В контексте системы типов, поддерживающей более высокие типы, мы можем различать собственные типы , типы, подобные Intили List[Int]от типов первого порядка, например, Listи типы более высокого типа, такие как Functorили Monad(типы, которые абстрагируются над типами, которые абстрагируются над типами).

    Система типов Java с другой стороны не поддерживает типы и, следовательно, не имеет типов «более высокого типа».

    Так что это должно быть видно на фоне системы вспомогательных типов.

  • В случае Scala вы часто видите примеры конструктора типа, такого как

     trait Iterable[A, Container[_]]

    с заголовком «Типы с более высоким родом», например, в Scala для универсальных программистов, раздел 4.3

    Это иногда missleading, потому что многие называют в Containerкачестве высшего kinded типа , а не Iterable, но что более точно,

    использование в Containerкачестве параметра конструктора типа здесь более высокого типа (более высокого порядка) Iterable.


80

Вид обычных типов , как Intи Char, чьи экземпляры значение, является *. Родов конструкторы одинарных типа как MaybeIS * -> *; конструкторы двоичного типа, такие как Either( карри ) * -> * -> *и т. д. Вы можете просматривать типы как Maybeи Eitherкак функции уровня типа: они принимают один или несколько типов и возвращают тип.

Функция более высокого порядка, если она имеет порядок больше 1, где порядок (неформально) - глубина вложения слева от стрелок функции:

  • Заказ 0: 1 :: Int
  • Заказ 1: chr :: Int -> Char
  • Заказ 2: fix :: (a -> a) -> a,map :: (a -> b) -> [a] -> [b]
  • Заказ 3: ((A -> B) -> C) -> D
  • Заказ 4: (((A -> B) -> C) -> D) -> E

Итак, короче говоря, тип с более высоким родом - это просто функция высшего порядка на уровне типа.

  • Заказ 0: Int :: *
  • Заказ 1: Maybe :: * -> *
  • Порядок 2: Functor :: (* -> *) -> Constraint—higher-kinded: конвертирует конструкторы унарного типа в ограничения класса типов

Хорошо, я понял, что тогда будет примером в Scala для (* ⇒ *) ⇒ * и (* ⇒ *) ⇒ (* ⇒ *)? Подойдет ли Функтор Ландея в первую категорию, а точнее во вторую?
Лутц

1
@lutz: Это было бы в первой категории: Functorпроизводит правильный тип (ну, черта, но та же идея) Functor[F[_]]из конструктора типов F.
Джон Пурди

1
@Jon: очень проницательный пост, спасибо. Можно (* => *) => (* => *)ли выразить конвертер типов в Scala? Если нет, на каком-либо другом языке?
Евгений Лабун

@JonPurdy Сравнение * ⇒ * ⇒ *с карри очень полезно. Спасибо!
Лифу Хуан,

(* ⇒ *) ⇒ (* ⇒ *)также может быть написано (* ⇒ *) ⇒ * ⇒ *. Это может быть выражено в Scala, как Foo[F[_], T]. Этот тип типа (в Хаскеле) newtype Twice f a = Twice (f (f a))(например, Twice Maybe IntMaybe (Maybe Int), Twice [] Char[[Char]]) или что-то более интересное, например, свободная монада data Free f a = Pure a | Free (f (Free f a)).
Джон Перди

37

Я бы сказал: тезисы более высокого типа над конструктором типов. Например рассмотреть

trait Functor [F[_]] {
   def map[A,B] (fn: A=>B)(fa: F[A]): F[B]
}

Вот Functor«тип с более высоким родом» (используемый в статье «Generics of the Higher Kind» ). Это не конкретный ("первого порядка") конструктор типа List(который абстрагируется только над собственными типами). Он абстрагируется от всех унарных («первого порядка») конструкторов типов (как обозначено F[_]).

Или, другими словами: в Java у нас есть конструкторы типов (например List<T>), но у нас нет «типов с более высоким родом», потому что мы не можем абстрагироваться над ними (например, мы не можем написать Functorинтерфейс, определенный выше - по крайней мере, не напрямую ).

Термин «полиморфизм высших порядков (конструктор типов)» используется для описания систем, которые поддерживают «высшие родовые типы».


Это то, что я подумал, но, похоже, это противоречит ответу Джона, где «конструктор конкретного типа» уже является «типом с более высоким родом».
Лутц

3
Да. Согласно ответу Джона (насколько я понимаю) List<T>в Java был бы конструктор унарного типа, поскольку он явно имеет вид * -> *. Чего не хватает в ответе Джона, так это того, что вы должны иметь возможность абстрагироваться над «целым» (а не только за секунду, *как в Java), чтобы назвать его типом с более высоким родом.
Landei

@Landai: в статье Scala для универсальных программистов в разделе 4.3 предлагается, чтобы черта Iterable [A, Container [_]] относилась к типу с более высоким родом (хотя неясно, подразумевается ли Iterator или Container), где на другой стороне vero690 в раздел 2.3.1 использует термин « конструктор типа с более высоким родом» для чего-то вроде (* -> *) -> * (оператор типа, параметризованный с помощью конструктора типа более высокого порядка), который выглядит как итератор или ваша черта Functor.
Лутц

1
Это, вероятно, правильно, но я думаю, что мы начинаем ломать голову здесь. Важный момент, касающийся типов с более высоким родством, заключается в том, что в них вовлечены не только конструкторы типов (полиморфизм конструкторов одного типа), но и то, что мы можем абстрагироваться от конкретного типа конструкторов этого типа (полиморфизм конструкторов типов высшего порядка). У нас есть возможность абстрагироваться от того, что мы хотим, без ограничений (относительно типов и конструкторов типов), что делает менее интересным назвать все возможные версии этой функции. И это вредит моему мозгу.
Landei

2
В общем, здесь важно различать определения и ссылки. Определение def succ(x: Int) = x+1вводит «конструктор значений» (см. Мой другой ответ о том, что я имею в виду под этим) succ(никто не назвал бы это значение succ (x: Int)). По аналогии, Functorэто (действительно более высокий род) тип, определенный в вашем ответе. Опять же , вы не должны относиться к нему как Functor[F[_]](что , Fчто? _Они не входят в комплект , к сожалению, синтаксический сахар для экзистенциалам мутит воды здесь делает?! F[_]Коротка для F[T forSome {type T}])
Адриаана мавров

1

Scala REPL предоставляет :kindкоманду, которая

scala> :help kind

:kind [-v] <type>
Displays the kind of a given type.

Например,

scala> trait Foo[A]
trait Foo

scala> trait Bar[F[_]]
trait Bar

scala> :kind -v Foo
Foo's kind is F[A]
* -> *
This is a type constructor: a 1st-order-kinded type.

scala> :kind -v Foo[Int]
Foo[Int]'s kind is A
*
This is a proper type.

scala> :kind -v Bar
Bar's kind is X[F[A]]
(* -> *) -> *
This is a type constructor that takes type constructor(s): a higher-kinded type.

scala> :kind -v Bar[Foo]
Bar[Foo]'s kind is A
*
This is a proper type.

В них :helpданы четкие определения, поэтому я думаю, что стоит опубликовать их здесь полностью (Scala 2.13.2).

scala> :help kind

:kind [-v] <type>
Displays the kind of a given type.

    -v      Displays verbose info.

"Kind" is a word used to classify types and type constructors
according to their level of abstractness.

Concrete, fully specified types such as `Int` and `Option[Int]`
are called "proper types" and denoted as `A` using Scala
notation, or with the `*` symbol.

    scala> :kind Option[Int]
    Option[Int]'s kind is A

In the above, `Option` is an example of a first-order type
constructor, which is denoted as `F[A]` using Scala notation, or
* -> * using the star notation. `:kind` also includes variance
information in its output, so if we ask for the kind of `Option`,
we actually see `F[+A]`:

    scala> :k -v Option
    Option's kind is F[+A]
    * -(+)-> *
    This is a type constructor: a 1st-order-kinded type.

When you have more complicated types, `:kind` can be used to find
out what you need to pass in.

    scala> trait ~>[-F1[_], +F2[_]] {}
    scala> :kind ~>
    ~>'s kind is X[-F1[A1],+F2[A2]]

This shows that `~>` accepts something of `F[A]` kind, such as
`List` or `Vector`. It's an example of a type constructor that
abstracts over type constructors, also known as a higher-order
type constructor or a higher-kinded type.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.