Что такое расширение DataKinds Haskell? - программирование
Подтвердить что ты не робот

Что такое расширение DataKinds Haskell?

Я пытаюсь найти объяснение расширения DataKinds, которое будет иметь смысл для меня, если я прочитал Learn You a Haskell. Есть ли стандартный источник, который будет иметь смысл для меня с тем, что я узнал?

Изменить: например, документация говорит

С -XDataKinds GHC автоматически продвигает каждый подходящий тип данных быть добрым, а его конструкторы (значения) должны быть конструкторами типов. Следующие типы

и дает пример

data Nat = Ze | Su Nat

возникают следующие типы и конструкторы типов:

Nat :: BOX
Ze :: Nat
Su :: Nat -> Nat

Я не понимаю. Хотя я не понимаю, что означает BOX, утверждения Ze :: Nat и Su :: Nat -> Nat, похоже, указывают, что обычно нормально, что Ze и Su являются нормальными конструкторами данных точно так, как вы ожидали бы видеть с помощью ghci

Prelude> :t Su
Su :: Nat -> Nat
4b9b3361

Ответ 1

Ну давай начнем с основ

Виды

Виды - это типы типов *, например

Int :: *
Bool :: *
Maybe :: * -> *

Обратите внимание, что -> перегружено, что означает "функция" и на уровне вида. Так что * это тип нормального типа Haskell.

Мы можем попросить GHCi напечатать что-то вроде :k.

Виды данных

Теперь это не очень полезно, так как у нас нет возможности делать свои собственные виды! С DataKinds, когда мы пишем

 data Nat = S Nat | Z

GHC будет способствовать этому, чтобы создать соответствующий вид Nat и

 Prelude> :k S
 S :: Nat -> Nat
 Prelude> :k Z
 Z :: Nat

Таким образом, DataKind делает такую систему расширяемой.

Пользы

Давайте сделаем пример прототипов с использованием ГАДЦ

 data Vec :: Nat -> * where
    Nil  :: Vec Z
    Cons :: Int -> Vec n -> Vec (S n)

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

Это основной обзор 10k футов.

* Это на самом деле продолжается, Values: Types: Kinds: Sorts... Некоторые языки (Coq, Agda...) поддерживают этот бесконечный стек вселенных, но Haskell объединяет все в один вид.

Ответ 2

Вот мой прием:

Рассмотрим вектор с индексом длины:

data Vec n a where
  Vnil  :: Vec Zero a
  Vcons :: a -> Vec n a -> Vec (Succ n) a

data Zero
data Succ a

Здесь у нас есть Kind Vec :: * -> * -> *. Так как вы можете представить вектор нулевой длины Int из:

Vect Zero Int

Вы также можете объявить бессмысленные типы:

Vect Bool Int

Это означает, что мы можем иметь нетипизированное функциональное программирование на уровне типа. Следовательно, мы избавляемся от такой двусмысленности, вводя виды данных и можем иметь такой вид:

Vec :: Nat -> * -> *

Итак, теперь наш Vec получает DataKind с именем Nat, который мы можем объявить как:

datakind Nat = Zero | Succ Nat

Введя новый тип данных, никто не может объявить бессмысленный тип, так как Vec теперь имеет более ограниченную сигнатуру вида.