J'essaie de trouver une explication de l'extension DataKinds qui aura du sens pour moi étant venue d'avoir lu seulement Learn You a Haskell . Existe-t-il une source standard qui me semble logique avec le peu que j'ai appris?
Edit: Par exemple, le documentation dit
Avec -XDataKinds, GHC promeut automatiquement chaque type de données approprié pour être un type, et ses constructeurs (valeur) pour être des constructeurs de type. Les types suivants
et donne l'exemple
data Nat = Ze | Su Nat
donnent naissance aux types et constructeurs de types suivants:
Nat :: BOX
Ze :: Nat
Su :: Nat -> Nat
Je ne comprends pas le point. Bien que je ne comprenne pas ce que signifie BOX
, les instructions Ze :: Nat
et Su :: Nat -> Nat
semble indiquer ce qui est déjà normalement le cas que Ze et Su sont des constructeurs de données normaux exactement comme vous vous attendez à voir avec ghci
Prelude> :t Su
Su :: Nat -> Nat
Commençons par les bases
Les types sont les types de types *, par exemple
Int :: *
Bool :: *
Maybe :: * -> *
Remarquerez que ->
est surchargé pour signifier "fonction" au niveau du type également. Donc *
est le type d'un type Haskell normal.
Nous pouvons demander à GHCi d'imprimer le genre de quelque chose avec :k
.
Maintenant, ce n'est pas très utile, car nous n'avons aucun moyen de faire nos propres sortes! Avec DataKinds
, quand on écrit
data Nat = S Nat | Z
GHC en fera la promotion pour créer le type correspondant Nat
et
Prelude> :k S
S :: Nat -> Nat
Prelude> :k Z
Z :: Nat
Donc DataKind
s rend le système aimable extensible.
Faisons l'exemple des types prototypiques à l'aide de GADT
data Vec :: Nat -> * where
Nil :: Vec Z
Cons :: Int -> Vec n -> Vec (S n)
Nous voyons maintenant que notre type Vec
est indexé par longueur.
C'est l'aperçu de base de 10k pieds.
* Cela continue en fait, Values : Types : Kinds : Sorts ...
Certains langages (Coq, Agda ..) supportent cette pile infinie d'univers, mais Haskell regroupe tout en une seule sorte.
Voici mon point de vue:
Considérons un vecteur de longueur indexé de type:
data Vec n a where
Vnil :: Vec Zero a
Vcons :: a -> Vec n a -> Vec (Succ n) a
data Zero
data Succ a
Ici, nous avons un genre Vec :: * -> * -> *
. Puisque vous pouvez représenter un vecteur de longueur nulle de Int par:
Vect Zero Int
Vous pouvez également déclarer des types dénués de sens:
Vect Bool Int
Cela signifie que nous pouvons avoir une programmation fonctionnelle non typée au niveau du type. Par conséquent, nous nous débarrassons de cette ambiguïté en introduisant des types de données et pouvons avoir un tel type:
Vec :: Nat -> * -> *
Alors maintenant, notre Vec
obtient un DataKind nommé Nat
que nous pouvons déclarer comme:
datakind Nat = Zero | Succ Nat
En introduisant un nouveau type de données, personne ne peut déclarer un type vide de sens puisque Vec
a maintenant une signature de type plus contrainte.