Вы затронули так много интересных вопросов в своем вопросе, поэтому я
боюсь, это будет длинный ответ:)
Вид (->)
Тип (->)
равен * -> * -> *
, если мы не примем во внимание размерность GHC
Вставки. Но округлости не происходит, ->
в
виды (->)
являются добрыми стрелками, а не функциональными стрелками. Действительно, чтобы
различать их добрые стрелки можно записать как (=>)
, а затем
вид (->)
равен * => * => *
.
Мы можем рассматривать (->)
как конструктор типа или, скорее, тип
оператор. Точно так же (=>)
можно рассматривать как оператор вида , и
как вы предлагаете в своем вопросе, нам нужно подняться на один уровень выше. Мы
Вернемся к этому позже в разделе Beyond Kinds , но сначала:
Как выглядит ситуация на языке с типизированной зависимостью
Вы спрашиваете, как выглядит сигнатура типа для функции, которая принимает
значение и возвращает тип. Это невозможно сделать в Haskell:
функции не могут возвращать типы! Вы можете смоделировать это поведение, используя
классы типов и семейства типов, но давайте для иллюстрации изменим
язык на зависимо типизированный язык
Agda . Это
язык с похожим синтаксисом, как у Haskell, где смешиваются типы
со значениями это вторая натура.
Чтобы было с чем работать, мы определяем тип данных естественного
числа, для удобства в одинарном представлении как в
Арифметика Пеано .
Типы данных написаны в
GADT стиль:
data Nat : Set where
Zero : Nat
Succ : Nat -> Nat
Set эквивалентен * в Haskell, "типе" всех (маленьких) типов,
такие как натуральные числа. Это говорит нам о том, что тип Nat
Set
, тогда как в Хаскеле у Ната не было бы типа, он имел бы
вид, а именно *
. В Агде нет видов, но все имеет
тип.
Теперь мы можем написать функцию, которая принимает значение и возвращает тип.
Ниже приведена функция, которая принимает натуральное число n
и тип,
и делает итерации List
конструктора n
, примененного к этому
тип. (В Агде [a]
обычно пишется List a
)
listOfLists : Nat -> Set -> Set
listOfLists Zero a = a
listOfLists (Succ n) a = List (listOfLists n a)
Некоторые примеры:
listOfLists Zero Bool = Bool
listOfLists (Succ Zero) Bool = List Bool
listOfLists (Succ (Succ Zero)) Bool = List (List Bool)
Теперь мы можем сделать функцию map
, которая работает на listsOfLists
.
Нам нужно взять натуральное число, которое является числом итераций
конструктора списка. Базовые случаи, когда число
Zero
, тогда listOfList
- это просто тождество, и мы применяем функцию.
Другой - пустой список, и пустой список возвращается.
Случай шага - небольшой шаг, включающий: мы применяем mapN
к голове
из списка, но это на один слой меньше вложенности, и mapN
к остальной части списка.
mapN : {a b : Set} -> (a -> b) -> (n : Nat) ->
listOfLists n a -> listOfLists n b
mapN f Zero x = f x
mapN f (Succ n) [] = []
mapN f (Succ n) (x :: xs) = mapN f n x :: mapN f (Succ n) xs
В типе mapN
аргумент Nat
называется n
, поэтому остальные
тип может зависеть от этого. Так что это пример типа, который
зависит от значения.
Как примечание, есть также две другие именованные переменные здесь,
а именно первые аргументы a
и b
типа Set
. Тип
переменные неявно повсеместно определены количественно в Haskell, но
здесь нам нужно разобрать их и указать их тип, а именно
Set
. Скобки предназначены для того, чтобы сделать их невидимыми в
определение, так как они всегда выводимы из других аргументов.
Набор абстрактный
Вы спрашиваете, каковы конструкторы (->)
. Стоит отметить одну вещь
является то, что Set
(как и *
в Haskell) является абстрактным: вы не можете
образец соответствия на нем. Так что это Агда незаконно:
cheating : Set -> Bool
cheating Nat = True
cheating _ = False
Опять же, вы можете смоделировать сопоставление с образцом на конструкторах типов в
Haskell, использующий семейства типов, один канонический пример дан на
Блог Брента Йорги .
Можем ли мы определить ->
в Агде? Так как мы можем возвращать типы из
функции, мы можем определить собственную версию ->
следующим образом:
_=>_ : Set -> Set -> Set
a => b = a -> b
(инфиксные операторы пишутся _=>_
, а не (=>)
)
определение имеет очень мало содержания, и очень похоже на
введите синоним в Haskell:
type Fun a b = a -> b
За пределами видов: Черепахи внизу
Как и было обещано выше, все в Агде имеет тип, но потом
тип из _=>_
должен иметь тип! Это касается вашей точки зрения
о родах, то есть, так сказать, на один уровень выше множества (видов).
В Агде это называется Set1
:
FunType : Set1
FunType = Set -> Set -> Set
И действительно, их целая иерархия! Указан тип
«малые» типы: типы данных в haskell. Но тогда у нас есть Set1
,
Set2
, Set3
и т. Д. Set1
это тип типов, который упоминает
Set
. Эта иерархия призвана избежать несоответствий, таких как у Жирара
Парадокс.
Как отмечено в вашем вопросе, ->
используется для типов и видов в
Haskell, и то же самое обозначение используется для функционального пространства вообще
уровни в Агде. Это должно рассматриваться как встроенный оператор типа,
и конструкторы лямбда-абстракция (или функция
определения). Эта иерархия типов аналогична настройке в
Система F омега и более
информация может быть найдена в последующих главах
Типы Пирса и языки программирования .
Системы чистого типа
В Agda типы могут зависеть от значений, а функции могут возвращать типы,
как показано выше, и у нас также была иерархия
типы. Систематическое исследование различных систем лямбда
исчисления более подробно исследованы в Pure Type Systems. Хороший
ссылка
Лямбда-исчисления с типами Барендрегом,
где PTS представлен на стр. 96, и множество примеров на стр. 99 и далее.
Вы также можете прочитать больше о лямбда-кубе там.