Dans une datadéclaration, un constructeur de type est la chose sur le côté gauche du signe égal. Le (s) constructeur (s) de données sont les éléments du côté droit du signe égal. Vous utilisez des constructeurs de type là où un type est attendu et vous utilisez des constructeurs de données là où une valeur est attendue.
Constructeurs de données
Pour simplifier les choses, nous pouvons commencer par un exemple de type qui représente une couleur.
data Colour = Red | Green | Blue
Ici, nous avons trois constructeurs de données. Colourest un type et Greenest un constructeur qui contient une valeur de type Colour. De même, Redet Bluesont tous deux des constructeurs qui construisent des valeurs de type Colour. Nous pourrions imaginer le pimenter cependant!
data Colour = RGB Int Int Int
Nous n'avons toujours que le type Colour, mais ce RGBn'est pas une valeur - c'est une fonction prenant trois Ints et renvoyant une valeur! RGBa le type
RGB :: Int -> Int -> Int -> Colour
RGBest un constructeur de données qui est une fonction prenant certaines valeurs comme arguments, puis les utilise pour construire une nouvelle valeur. Si vous avez effectué une programmation orientée objet, vous devez le reconnaître. En POO, les constructeurs prennent également certaines valeurs comme arguments et renvoient une nouvelle valeur!
Dans ce cas, si nous appliquons RGBà trois valeurs, nous obtenons une valeur de couleur!
Prelude> RGB 12 92 27
#0c5c1b
Nous avons construit une valeur de type Colouren appliquant le constructeur de données. Un constructeur de données contient une valeur comme le ferait une variable ou prend d'autres valeurs comme argument et crée une nouvelle valeur . Si vous avez déjà fait de la programmation, ce concept ne devrait pas vous être très étrange.
Entracte
Si vous voulez construire un arbre binaire pour stocker Strings, vous pouvez imaginer faire quelque chose comme
data SBTree = Leaf String
            | Branch String SBTree SBTree
Ce que nous voyons ici est un type SBTreequi contient deux constructeurs de données. En d'autres termes, il existe deux fonctions (à savoir Leafet Branch) qui construiront des valeurs de SBTreetype. Si vous n'êtes pas familier avec le fonctionnement des arbres binaires, accrochez-vous simplement. Vous n'avez pas vraiment besoin de savoir comment fonctionnent les arbres binaires, seulement que celui-ci stocke les Strings d'une manière ou d'une autre.
Nous voyons également que les deux constructeurs de données prennent un Stringargument - c'est la chaîne qu'ils vont stocker dans l'arborescence.
Mais! Et si nous voulions également pouvoir stocker Bool, nous devions créer un nouvel arbre binaire. Cela pourrait ressembler à ceci:
data BBTree = Leaf Bool
            | Branch Bool BBTree BBTree
Constructeurs de type
Les deux SBTreeet BBTreesont des constructeurs de type. Mais il y a un problème flagrant. Voyez-vous à quel point ils sont similaires? C'est le signe que vous voulez vraiment un paramètre quelque part.
Nous pouvons donc faire ceci:
data BTree a = Leaf a
             | Branch a (BTree a) (BTree a)
Maintenant, nous introduisons une variable de type en a tant que paramètre du constructeur de type. Dans cette déclaration, BTreeest devenue une fonction. Il prend un type comme argument et renvoie un nouveau type .
  Il est important ici de considérer la différence entre un type concret (les exemples incluent Int, [Char]et Maybe Bool) qui est un type qui peut être attribué à une valeur dans votre programme, et une fonction de constructeur de type dont vous avez besoin pour alimenter un type pour pouvoir être assigné à une valeur. Une valeur ne peut jamais être de type "liste", car elle doit être une "liste de quelque chose ". Dans le même esprit, une valeur ne peut jamais être de type "arbre binaire", car elle doit être un "arbre binaire stockant quelque chose ".
Si nous passons, disons, Boolcomme argument à BTree, il renvoie le type BTree Bool, qui est un arbre binaire qui stocke Bools. Remplacez chaque occurrence de la variable de type apar le type Bool, et vous pourrez voir par vous-même comment c'est vrai.
Si vous le souhaitez, vous pouvez voir BTreecomme une fonction avec le genre
BTree :: * -> *
Les types sont un peu comme des types - le *indique un type concret, donc nous disons qu'il BTreeva d'un type concret à un type concret.
Emballer
Revenez ici un moment et prenez note des similitudes.
- Un constructeur de données est une «fonction» qui prend 0 ou plusieurs valeurs et vous renvoie une nouvelle valeur. 
- Un constructeur de type est une "fonction" qui prend 0 ou plusieurs types et vous redonne un nouveau type. 
Les constructeurs de données avec des paramètres sont sympas si nous voulons de légères variations dans nos valeurs - nous mettons ces variations dans les paramètres et laissons le créateur de la valeur décider quels arguments ils vont mettre. Dans le même sens, les constructeurs de types avec des paramètres sont cool si nous voulons de légères variations dans nos types! Nous mettons ces variations comme paramètres et laissons le type qui crée le type décider des arguments qu'il va mettre.
Une étude de cas
Comme la dernière ligne droite ici, nous pouvons considérer le Maybe atype. Sa définition est
data Maybe a = Nothing
             | Just a
Voici Maybeun constructeur de type qui renvoie un type concret. Justest un constructeur de données qui renvoie une valeur. Nothingest un constructeur de données qui contient une valeur. Si nous regardons le type de Just, nous voyons que
Just :: a -> Maybe a
En d'autres termes, Justprend une valeur de type aet renvoie une valeur de type Maybe a. Si nous regardons le genre de Maybe, nous voyons que
Maybe :: * -> *
En d'autres termes, Maybeprend un type concret et renvoie un type concret.
Encore une fois! La différence entre un type concret et une fonction constructeur de type. Vous ne pouvez pas créer une liste de Maybes - si vous essayez d'exécuter
[] :: [Maybe]
vous obtiendrez une erreur. Vous pouvez cependant créer une liste de Maybe Int, ou Maybe a. C'est parce que Maybec'est une fonction de constructeur de type, mais une liste doit contenir des valeurs d'un type concret. Maybe Intet Maybe asont des types concrets (ou si vous le souhaitez, des appels à des fonctions de constructeur de type qui renvoient des types concrets.)
               
              
Cars'agit à la fois d'un constructeur de type (sur le côté gauche du=) et d'un constructeur de données (sur le côté droit). Dans le premier exemple, leCarconstructeur de type n'accepte aucun argument, dans le second, il en prend trois. Dans les deux exemples, leCarconstructeur de données prend trois arguments (mais les types de ces arguments sont dans un cas fixes et dans l'autre paramétrés).