Beaucoup de langages fortement typés autorisent les types paramétrés par des types (souvent appelés types génériques).
Coq autorise en plus les types paramétrés par des valeurs.
Pourquoi paramétrer un type par des valeurs ?
Parce que certaines opérations sur ce type de données ne sont possibles que pour certaines valeurs.
Par exemple 1|2 2|3 3|4 est une chaîne de dominos autorisée.
Tandis que 2|1 2|3 4|3 est une chaîne de dominos interdite.
D'où l'idée intuitive : paramétrons le type domino
par un entier à gauche et un entier à droite.
Inductive domino : nat -> nat -> Type
Ensuite on ajoute block
le constructeur de base et chain
le constructeur composite.
Inductive domino : nat -> nat -> Type := | block: forall m n, domino m n | chain: forall m n p, domino m n -> domino n p -> domino m p.
À partir de là Coq est capable de garantir (statiquement, à la compilation) qu'à l'exécution aucune chaîne invalide de dominos ne sera produite.
Création de la chaîne 1|2 2|3 :
Coq < Eval compute in chain 1 2 3 (block 1 2) (block 2 3). = chain 1 2 3 (block 1 2) (block 2 3) : domino 1 3
Le résultat est bien un domino 1|3
Félicitations pour le premier article créé sur la V9 !
Je n'ai pas bien compris où étaient les valeurs paramètres du coup. Si tu paramètres par un entier à gauche et un entier à droite, ne paramètres-tu par par type ?
Le mieux que je puisse faire pour t'expliquer c'est un message d'erreur de typage.
Par exemple la tentative de création de la chaîne 2|1 2|3 :
Se solde par un échec car le type
domino 2 3
n'est pas le type attendu.Pour le coup j'ai parfaitement compris. Autre chose : dans ta définition tu n'as pas limité le chiffrage des dominos, il pourrait y avoir n'importe quel entier. Est-ce qu'il y a un moyen de limiter la fourchette de valeurs entre 1 et 6 ?
Déjà avec
nat
on élimine les entiers négatifs.Si on souhaite restreindre davantage il y a au moins deux façons de le faire.
Vu qu'on n'utilise pas d'opération sur les
nat
on peut créer un type énuméré qui va de 1 à 6 :Le type
domino
devient alors :(Il faut toujours 2 valeurs
dice
pour instancier leType
domino)La seconde façon de faire c'est d'inclure la contrainte dans le constructeur
block
:Avantage : On dispose toujours des opérations dans
nat
.Inconvénient : Créer un
block
devient plus laborieux car on doit prouver qu'on respecte les bornes. On va créer une petite fonctiondice
pour simplifier la ligneblock
.Normalement on préfère la 1ière façon car elle ne génére pas de nouvelle obligation de preuve, les valeurs étant d'emblée restreintes par la définition du type.
L'arbre de Fibonacci
Un autre
Type
paramétré par une valeur entière.Tu aurais un exemple d'utilisation de ce type ?
C'est pas comme si c'était un exemple pratique
C'est la limite théorique d'un tas de Fibonacci quand le nombre d'éléments tend vers l'infini.
Les exemples plus concrets il y en a plein, la plupart du temps il s'agit d'expliciter une borne dans le type du conteneur pour garantir l'accès indicé.
C'est de cas de
vector
dans la bibliothèque standard :vector
est paramétré par un typeA
et par une valeur de ℕ (la longueur de la liste).