Les types de données algébriques vous permettent de définir des types de manière récursive. Concrètement, supposons que nous ayons le type de données
datalist=Nil|ConsofN×list
Cela signifie que est le plus petit ensemble généré par les opérateurs N i l et C o n s . On peut formaliser cela en définissant l'opérateur F ( X )listNilConsF(X)
F(X)=={Nil}∪{Cons(n,x)|n∈N∧x∈X}
puis définir commelist
list=⋃i∈NFi(∅)
Un ADT généralisé est ce que nous obtenons lorsque nous définissons un opérateur de type de manière récursive. Par exemple, nous pouvons définir le constructeur de type suivant:
b u s ha = L e a fo fune|N e s to fb u s h ( a × a )
Ce type signifie qu'un élément de est un tuple de a s de longueur 2 n pour certains n , puisque chaque fois que nous entrons dans le constructeur N e s t l'argument type est apparié avec lui-même. Nous pouvons donc définir l'opérateur que nous voulons prendre un point fixe comme:b u s huneune2nnN e s t
F( R ) = λ X.{ L e a f( x )|x ∈ X} ∪ { N e s t ( v )|v ∈ R ( X) }
Un type inductif dans Coq est essentiellement un GADT, où les index de l'opérateur de type ne sont pas limités à d'autres types (comme dans, par exemple, Haskell), mais peuvent également être indexés par des valeurs de la théorie des types. Cela vous permet de donner des types pour les listes indexées en longueur, etc.
Merci. Mais cela ne signifierait-il pas simplement que "type inductif" est complètement synonyme de "type dépendant"?
ninjagecko
4
@Neel: Je n'ai jamais vu de types comme les bushGADT. Je les ai vus appelés types imbriqués ou non réguliers.
jbapple
3
Les types imbriqués sont un cas particulier des GADT. La caractéristique critique d'un GADT est simplement qu'il s'agit d'une définition récursive de type supérieur. (Les modifications apportées à la rhs sont essentiellement du sucre syntaxique pour ajouter une égalité de type en tant que composant du constructeur.)
Neel Krishnaswami
4
@ninjagecko: Les "types inductifs" sont des types dont la sémantique est le point le moins fixe d'un constructeur. Tous les types ne peuvent pas être décrits de cette façon (les fonctions ne le peuvent pas, pas plus que les types infinis tels que les flux). Les types dépendants décrivent les types qui permettent aux termes du programme de s'y produire (c'est-à-dire que les types peuvent "dépendre" des termes). Puisque Coq est une théorie de type dépendante, les types inductifs qu'elle vous permet de définir sont également dépendants. Mais les théories des types non dépendants peuvent également prendre en charge les types inductifs, et ces types inductifs ne seront pas dépendants.
Neel Krishnaswami
2
@NeelKrishnaswami: Seriez-vous assez aimable pour clarifier votre réponse en énumérant les "premiers plus petits" éléments des types de bush a? Dans cet exemple, est-ce Nest Leaf(a) Leaf(a) Leaf(a) Leaf(a), ou Nest ((Nest Leaf(a) Leaf(a)) (Nest Leaf(a) Leaf(a)))comme un exemple de l'ensemble?
ninjagecko
19
Considérez les types de données algébriques tels que:
data List a = Nil | Cons a (List a)
Les types de retour de chaque constructeur dans un type de données sont tous les mêmes: Nilet les Consdeux retournent List a. Si nous permettons aux constructeurs de renvoyer différents types, nous avons un GADT :
data Empty -- this is an empty data declaration; Empty has no constructors
data NonEmpty
data NullableList a t where
Vacant :: NullableList a Empty
Occupied :: a -> NullableList a b -> NullableList a NonEmpty
Occupieda le type a -> NullableList a b -> NullableList a NonEmpty, tout en Consa le type a -> List a -> List a. Il est important de noter qu'il NonEmptys'agit d'un type et non d'un terme. Un autre exemple:
data Zero
data Succ n
data SizedList a t where
Alone :: SizedList a Zero
WithFriends :: a -> SizedList a n -> SizedList a (Succ n)
Les types inductifs dans les langages de programmation qui ont des types dépendants permettent aux types de retour des constructeurs de dépendre des valeurs (et pas seulement des types) des arguments.
Inductive Parity := Even | Odd.
Definition flipParity (x:Parity) : Parity :=
match x with
| Even => Odd
| Odd => Even
end.
Fixpoint getParity (x:nat) : Parity :=
match x with
| 0 => Even
| S n => flipParity (getParity n)
end.
(*
A ParityNatList (Some P) is a list in which each member
is a natural number with parity P.
*)
Inductive ParityNatList : option Parity -> Type :=
Nil : forall P, ParityNatList P
| Cons : forall (x:nat) (P:option Parity),
ParityNatList P -> ParityNatList
(match P, getParity x with
| Some Even, Even => Some Even
| Some Odd, Odd => Some Odd
| _, _ => None
end).
Merci. "Types inductifs dans les langages de programmation qui ont des types dépendants" A quoi ressemblerait alors un type inductif dans un langage sans types dépendants, et pouvez-vous avoir des types dépendants non inductifs (mais de type GADT)?
bush
GADT. Je les ai vus appelés types imbriqués ou non réguliers.bush a
? Dans cet exemple, est-ceNest Leaf(a) Leaf(a) Leaf(a) Leaf(a)
, ouNest ((Nest Leaf(a) Leaf(a)) (Nest Leaf(a) Leaf(a)))
comme un exemple de l'ensemble?Considérez les types de données algébriques tels que:
Les types de retour de chaque constructeur dans un type de données sont tous les mêmes:
Nil
et lesCons
deux retournentList a
. Si nous permettons aux constructeurs de renvoyer différents types, nous avons un GADT :Occupied
a le typea -> NullableList a b -> NullableList a NonEmpty
, tout enCons
a le typea -> List a -> List a
. Il est important de noter qu'ilNonEmpty
s'agit d'un type et non d'un terme. Un autre exemple:Les types inductifs dans les langages de programmation qui ont des types dépendants permettent aux types de retour des constructeurs de dépendre des valeurs (et pas seulement des types) des arguments.
Remarque: GHC dispose d'un mécanisme pour traiter les constructeurs de valeur comme des constructeurs de type . Ce n'est pas la même chose que les types inductifs dépendants de Coq, mais cela diminue quelque peu la charge syntaxique des GADT et cela peut conduire à de meilleurs messages d'erreur.
la source