D'abord une explication terminologique: les positions négatives et positives viennent de la logique. Ils sont sur une asymétrie dans connecteurs logiques: en l' A se comporte différemment de B . Une chose similaire se produit dans la théorie des catégories, où nous disons contravariant et covariant au lieu de négatif et positif, respectivement. En physique, ils parlent de quantités qui se comportent "de manière covariante" et "contravariante aussi. C'est donc un phénomène très général. Un programmeur pourrait les considérer comme" entrée "et" sortie ".A ⇒ BUNEB
Passons maintenant aux types de données inductifs.
Considérez un type de données inductive comme une sorte de structure algébrique: constructeurs sont les opérations qui ont des éléments de T comme arguments et produire de nouveaux éléments de T . C'est très similaire à l'algèbre ordinaire: l'addition prend deux nombres et produit un nombre.TTT
En algèbre, il est habituel qu'une opération prenne un nombre fini d'arguments, et dans la plupart des cas, elle prend zéro (constant), un (unaire) ou deux (binaire) arguments. Il est commode de généraliser cela pour les constructeurs de types de données. Supposons que cc'est un constructeur pour un type de données T:
- si
cest une constante, nous pouvons la considérer comme une fonction unit -> T, ou de manière équivalente (empty -> T) -> T,
- si
cest unaire, nous pouvons le considérer comme une fonction T -> T, ou de manière équivalente (unit -> T) -> T,
- si
cest binaire, nous pouvons le considérer comme une fonction T -> T -> T, ou de manière équivalente T * T -> T, ou équivalente (bool -> T) -> T,
- si nous voulions un constructeur
cqui prend sept arguments, nous pourrions le voir comme une fonction (seven -> T) -> Toù se seventrouve un type précédemment défini avec sept éléments.
- nous pouvons également avoir un constructeur
cqui prend une infinité d'arguments, ce serait une fonction (nat -> T) -> T.
Ces exemples montrent que la forme générale d'un constructeur doit être
c : (A -> T) -> T
où nous appelons Al' arité de cet nous pensons ccomme un constructeur qui prend A-nombreux arguments de type Tpour produire un élément de T.
Voici quelque chose de très important: les arités doivent être définies avant de définir T, sinon nous ne pouvons pas dire ce que les constructeurs sont censés faire. Si quelqu'un essaie d'avoir un constructeur
broken: (T -> T) -> T
puis la question "combien d'arguments brokenfaut-il?" n'a pas de bonne réponse. Vous pouvez essayer d'y répondre avec "il faut T-de nombreux arguments", mais cela ne fonctionnera pas, car il Tn'est pas encore défini. Nous pourrions essayer de sortir du cunundrum en utilisant une théorie de point fixe sophistiquée pour trouver un type Tet une fonction injective (T -> T) -> T, et réussirions, mais nous briserions également le principe d'induction pour le Tlong du chemin. Donc, c'est juste une mauvaise idée d'essayer une telle chose.
λvλ ⋅ vcB
c : B * (A -> T) -> T
En effet, de nombreux constructeurs peuvent être réécrits de cette façon, mais pas tous, nous avons besoin d'une étape de plus, à savoir que nous devrions permettre Ade dépendre de B:
c : (∑ (x : B), A x -> T) -> T
Il s'agit de la forme finale d'un constructeur pour un type inductif. C'est aussi précisément ce que sont les types W. La forme est si générale que nous n'avons besoin que d'un seul constructeur c! En effet, si nous en avons deux
d' : (∑ (x : B'), A' x -> T) -> T
d'' : (∑ (x : B''), A'' x -> T) -> T
alors nous pouvons les combiner en un seul
d : (∑ (x : B), A x -> T) -> T
où
B := B' + B''
A(inl x) := A' x
A(inr x) := A'' x
Soit dit en passant, si nous curry la forme générale, nous voyons qu'elle est équivalente à
c : ∏ (x : B), ((A x -> T) -> T)
ce qui est plus proche de ce que les gens écrivent réellement dans les assistants de preuve. Les assistants de preuve nous permettent d'écrire les constructeurs de manière pratique, mais ceux-ci sont équivalents à la forme générale ci-dessus (exercice!).
Ala pile et éventuellement l'exploser (dans les langages basés sur la pile).