Commit 4d513c3b authored by Pierre Letouzey's avatar Pierre Letouzey

déménagement des fichiers Coq vers le dépôt coq-lmfi

parent f939754f
Cours de programmation fonctionnelle en Coq (M2 LMFI, Paris Diderot)
====================================================================
Ancien dépôt du cours de programmation fonctionnelle en Coq (M2 LMFI, Université de Paris)
==========================================================================================
Note: le sous-répertoire `ocaml` contient:
**Les fichiers sont [maintenant ici](https://gitlab.math.univ-paris-diderot.fr/letouzey/coq-lmfi/tree/master/1-prog)** dans un dépôt regroupant les deux parties du cours (programmation et preuves).
Il ne reste ici que le sous-répertoire `ocaml` contenant:
- les notes des séances de pré-rentrée (initiation à la programmation OCaml)
- des feuilles de TD en OCaml pour l'ancienne mouture de ce module (Modèles de la Programmation, en OCaml)
### Projet
A suivre très bientôt
This diff is collapsed.
Introduction à la Programmation Fonctionnelle en Coq
====================================================
**M2 LMFI**
## Démarrage
Il y a plusieurs manières d'utiliser Coq:
* via `coqide`, une interface graphique basée sur `gtk`
* via `proofgeneral`, qui est un mode pour `emacs`
* directement dans son navigateur en utilisant `jsCoq`, p.ex. https://jscoq.github.io/node_modules/jscoq/examples/scratchpad.html
(voir https://github.com/ejgallego/jscoq pour le mode d'emploi)
* ou éventuellement en lançant `coqtop`, une boucle d'interaction textuelle assez frustre à la `ocaml`
Chaque méthode a ses aficionados (même la dernière...).
Par convention, les fichiers Coq utilisent l'extension `.v` (pour "vernaculaire"...).
Une fois lancées, les interfaces `coqide`, `proofgeneral` et `jsCoq` proposent une disposition assez similaire : le fichier en cours d'édition est à gauche, tandis que les preuves en cours seront affichées en haut à droite, et les messages du système en bas à droite (réponses de Coq ou messages d'erreurs). La portion du fichier déjà soumise à Coq est indiquée par des couleurs, et ces interfaces permettent de faire descendre cette zone, en envoyant une ou plusieurs phrases à Coq, ou au contraire de remonter (retour à un ancien état de Coq).
Dans ce cours nous allons essentiellement utiliser les commandes suivantes:
* `Definition` : associe un nom à un terme Coq (non-récursif)
* `Fixpoint` : idem pour une définition récursive
* `Inductive` : création d'un nouveau type (inductif)
* `Check` : afficher le type d'un terme Coq
* `Print` : afficher le corps d'une définition ou le détail d'un type inductif
* `Compute` : calculer un terme, c'est-à-dire demander sa forme normale.
Un point `.` sert de terminateur à chaque phrase Coq.
## Coeur fonctionnel de Coq
Présentation du lambda-calcul, avec ses trois constructions de base :
- variables
- abstraction de fonction : `λx.t` (correspondant à `fun x => t` en Coq)
- application de fonction : `t u` (idem en OCaml)
Règle de calcul : la β-réduction où `(λx.t) u` donne `t{x:=u}` (la définition de la substitution est laissée en exercice).
Exemple de propriété théorique de la réduction du lamda-calcul : la confluence.
Exemple de terme dont la réduction est infinie : `ΔΔ` valant `(λx.(x x))(λx.(x x))`.
Pas d'équivalent en Coq pour des raisons de typage.
Typage simple du lambda-calcul :
- On type les variables en regardant dans un environnement de typage Γ
- Si `Γ+x:τ ⊢ t:σ` alors `Γ ⊢ (λx.t):(τ→σ)`
- Si `Γ ⊢ t:(τ→σ)` et `Γ ⊢ u:τ` alors `Γ ⊢ (t u) : σ`
Lien avec la logique minimale (gérant uniquement l'implication) : il suffit de ne garder que les types dans les règles précédentes.
C'est (le début de) l'isomorphisme de Curry-Howard.
Le typage de Coq est une évolution de ces règles de départ.
Propriétés essentielles du lambda-calcul simplement typé :
- Préservation du typage lors de la réduction
- Normalisation forte : un terme bien typé ne peut avoir de réduction infinie.
Ceci combiné à la confluence signifie que la réduction d'un terme `t` finit toujours en temps fini sur une unique forme normale `t₀` de `t`.
Même si le lambda-calcul de Coq (nommé CIC pour "Calculus of Inductive Construction") est bien plus riche, il satisfait encore ces propriétés.
Note: la terminaison de tous les calculs n'est normalement *pas* une propriété souhaitable pour un langage de programmation (cf par exemple la récursion générale d'Ocaml : `let rec`). Pour Coq ce choix permet de garantir l'absence de preuves closes de `False`. On verra par la suite l'impact de ce choix sur le programmeur.
## Un premier point sur les types Coq
Pas de différences syntaxiques entre les types Coq et les autres termes, en Coq tout est terme.
Moralement, un type est quelque chose qui peut être à droite d'un jugement de typage `Γ ⊢ t:τ`.
On peut aussi se poser la question du type d'un type. En Coq un type de type va forcément être une *sorte* ou (univers), à savoir `Type`, `Set` ou `Prop`.
* `Type` est la sorte la plus générale en Coq.
* `Prop` sert à exprimer des propriétés logiques, on le verra très peu dans ce cours
* `Set` est un alias désuet pour un cas particulier de `Type`
Pour éviter des paradoxes liés à `Γ ⊢ Type : Type`, il n'y a pas un univers `Type` mais une hiérarchie `Type₀ : Type₁ : Type₂ : ...`.
Normalement ces indices sont cachés à l'utilisateur, et on n'aura pas besoin de rentrer dans ces considérations.
En Coq, le type flèche `A->B` n'est pas primitif, c'est un cas particulier d'une construction plus générale, le *produit* `∀x:A,B` (syntaxe Coq `forall x:A, B`). Lorsque la variable `x` n'apparaît pas dans `B` (produit *non-dépendant*), on écrit `A->B`. Pour un premier exemple de produit dépendant, voir par exemple la définition de l'identité dans la section suivante.
En première approximation, la règle de typage d'un produit ressemble à ceci:
- Si `Γ ⊢ A:Type` et si `Γ+x:A ⊢ B:Type` alors `Γ ⊢ (forall x:A,B) : Type`
En réalité, il faudrait se préoccuper des indices des univers `Type` : le dernier est le max des deux précédents. Et cette règle de typage a également une variante pour `Prop`, qui ne nous intéresse pas ici.
On généralise alors les règles de typage des fonctions et applications:
- Si `Γ+x:A ⊢ t:B` alors `Γ ⊢ (fun x => t):(forall x:A, B)`
- Si `Γ ⊢ t:(forall x:A,B)` et `Γ ⊢ u:A` alors `Γ ⊢ (t u) : B{x:=u}`
Notez que pour un produit non-dépendant, on retrouve les anciennes règles pour `A->B`. En particulier, si `x` n'apparaît pas dans `B` alors `B{x:=u} = B`.
## Constantes Coq
Outre des variables et leurs types, l'environnement `Γ` de Coq peut également contenir des "constantes" `(c:t:=u)``c` est le nom de la constante, et `t` et `u` sont deux termes Coq donnant le type et le corps de cette constante.
Evidemment, le système vérifie `Γ ⊢ u:t` avant d'accepter l'ajout de cette constante `c` à l'environnement.
Une règle de réduction nommée `δ` (delta) permet à tout moment de remplacer `c` par son corps `u`.
Attention au vocabulaire, comme `u` peut être un `fun`, notre constante peut être une fonction, donc pas si "constante" que cela.
Syntaxe d'ajout d'une constante globale au système:
```coq
Definition c : t := u.
```
Si Coq peut "inférer" le type `t` à partir du corps `u` de la définition, la partie `: t` est alors optionnelle.
Pour une définition de fonction (corps débutant par `fun`), on peut également placer les arguments juste après le nom de la fonction.
Par exemple les lignes suivantes sont équivalentes :
```coq
Definition id_1 : forall X, X->X := fun (X:Type)(x:X) => x.
Definition id_2 : forall X, X->X := fun X x => x. (* type inference in fun *)
Definition id_3 := fun (X:Type)(x:X) => x. (* inference of the constant type *)
Definition id_4 (X:Type)(x:X) : X := x. (* constant with arguments after the constant name *)
Definition id_5 (X:Type)(x:X) := x. (* same, without explicit constant type *)
Definition id_6 X (x:X) := x. (* default sort is Type *)
```
Coq dispose également d'une syntaxe `let ... in` permettant de nommer localement des termes.
```
Definition test :=
let id := fun X (x:X) => x in
let id2 X := id (X->X) (id X) in
let id4 X := id2 (X->X) (id2 X) in
id4.
```
Un `let x:=t in u` se comporte quasiment comme `((fun x=>u) t)`.
Là encore, une règle de réduction (`ζ`, zeta) permet de supprimer cette abbréviation locale en remplaçant partout `x` par `t` dans `u`.
## Premiers types de données : Booléens et Entiers
Coq fournit le type `bool` et ses constantes `true` et `false`.
On dispose d'une construction `if ... then ... else ...`.
Quelques opérations booléennes :
- la negation : `negb`
- le "et" logique : `andb` (syntaxe `&&` après un `Open Scope bool_scope`)
- le "ou" logique : `orb` (syntaxe `||`)
Attention, contrairement aux langages usuels, l'évaluation de `&&` et `||` n'est pas forcément *paresseuse* en Coq.
Pour la suite, chargez la bibliothèque `Arith`:
```coq
Require Import
```
Coq fournit un type `nat` des entiers naturels. Attention c'est un codage "unaire" (entiers de Peano) donc extraordinairement lent.
Quelques opérations sur les entiers : addition `+`, multiplication `*`, division entière `/`, modulo `x mod y`.
On disposera de comparaisons sur les entiers : test d'égalité `x =? y` ou d'ordre `x <? y` ou `x <=? y`, etc.
Attention en Coq 8.4 il faut charger également la bibliothèque ̀NPeano` et installer une notation manquante:
```coq
Infix "=?" := Nat.eqb (at level 70, no associativity) : nat_scope.
```
On verra par la suite des structures d'entiers plus efficaces (codage binaire) et/ou étendu aux nombres relatifs (type `Z`).
## Recursivité
`Fixpoint` permet de réutiliser la fonction qu'on est en train d'écrire !
Avant d'accepter un `Fixpoint`, Coq vérifie que cette définition récursive est visiblement décroissante. Cela se fait selon un critère de décroissance *structurelle* que nous alors revoir plus en détail par la suite. En résumé, les appels récursifs doivent avoir lieu sur des *sous-termes stricts*. En pratique, cela signifie utiliser la construction `match ... with ... end` pour obtenir (par exemple) l'entier immédiatement précédent celui de départ.
```coq
Fixpoint factorial (n:nat) :=
match n with
| 0 => 1
| S m => (factorial m) * n
end.
```
Ce critère est très contraignant. Par exemple ici remplacer le `factorial m` par un `factorial (n-1)` est refusé !
## Fonctions de première classse et application partielle
Des fonctions en argument ou en réponse ...
Des arguments qui manquent ...
Functional Programming in Coq (session 2)
=========================================
**M2 LMFI**
## Universe constraints
A followup of session 1 : some (ab)use of Coq universes are rejected by the system, since they endanger the logical soundness. The reason is similar to Russel's paradox, it is known as the [Hurkens' paradox](https://coq.inria.fr/library/Coq.Logic.Hurkens.html) in type theory.
See [corrections/td1.v](corrections/td1.v) for an example of *universe inconsistency* when defining `church_minus` (additional question after exercice 3). Since `church` is `forall X, (X->X)->(X->X)` here we would like to form `church church` and have it equivalent to `(church->church)->(church->church)`. This amounts to replacing variable `X` (of a certain `Type_i`) by the whole `church` itself, but here `church` can only be in `Type_(i+1)` or more (try this typing yourself!) . This `church church` application is hence not doable when universe levels are fixed at the time `church` is defined. A solution here with a modern Coq : activate *universe polymorphism*, and let Coq pick universe levels when a definition is *used*, not when it is defined. This helps greatly in practice (but not always).
## General recursivity and logical consistence
Coq is logically sound as long as we cannot produce a *closed* proof of `False`, a type which is normally empty. Here *closed* means without variables nor axioms in the typing environment. Without even knowing how `False` is defined in Coq, a fully general recursivity would give us such a proof. Reminder : in Coq there is no syntactic distinction between proofs and programs.
```coq
Fixpoint loop (n:nat) : False := loop n
Definition boom : False := loop 0.
```
Obviously such a definition is rejected by Coq. Here is the `OCaml` equivalent of this code (no question of logical soundness in this case):
```ocaml
let rec loop (n:int) : 'a = loop n
let any : 'a = loop 0 (* Type-checking ok, but then the evaluation loops as expected *)
```
Similarly, Coq relies crucially on the property that a closed term in an *inductive* type (see next section) will evaluate (we say also "reduce") to one of the constructors of this type, followed by the right number of arguments. This allows to derive properties such as : all boolean expression is either equal to ``true` or to `false`, all natural number of type `nat` is either zero or a successor, etc.
Once again, an unrestricted general recursivity would break this property. For example:
```coq
Fixpoint flipflop (b:bool) := negb (flipflop b).
Definition alien : flipflop true.
```
If `flipflop` would be accepted by Coq (it is not!), we would have the equation `flipflop true = negb (flipflop true)`, and hence `alien = negb alien`. This `alien` cannot hence be `true`, nor `false`.
## Inductive types
The keyword `Inductive` allow to enrich the system with a new type definition, expressed via several *constructor* rules. The general syntax of a inductive type declaration is :
```coq
Inductive t :=
| C₁ : A₁₁ -> ... -> A₁ₚ -> t
| ...
| Cₙ : Aₙ₁ -> ... -> Aₙₖ -> t
```
The `Cᵢ` are *constructors* of type `t`, they may require some arguments (or not), but anyway they always have `t` as result type (after the rightmots arrow).
In fact, `t` itselft may have arguments, turning it into an *inductive type scheme* (we also say *inductive predicate*). We'll see examples of that later.
Basic examples (already in the Coq standard library, no need to copy-paste them).
```coq
Inductive bool :=
| true : bool
| false : bool.
Inductive nat :=
| O : nat
| S : nat -> nat.
```
## Positivity constraints
Some inductive declarations are rejected by Coq, once again for preserving logical soundness. Roughly speaking, the inductive type being currently declared cannot appear as argument of an arguments of a constructor of this type. This condition is named *strict positivity*.
Illustration of the danger, in OCaml:
```ocaml
(* First, a "lambda-calcul" version *)
type lam = Fun : (lam -> lam) -> lam (* In the type of Fun, the leftmost "lam" would be a non-positive occurrence in Coq *)
let identity = Fun (fun t -> t)
let app (Fun f) g = f g
let delta = Fun (fun x -> app x x)
let dd = app delta delta (* infinite evaluation, even without "let rec" ! *)
(* Second, a version producing a infinite computation in any type (hence could be in Coq's False) *)
type 'a poly = Poly of ('a poly -> 'a)
let app (Poly f) g = f g
let delta = Poly (fun x -> app x x)
let dd : 'a = app delta delta
```
In Coq, this term `dd` would be a closed proof of `False` is these kinds of inductive types would be accepted. Once again, this is also closely related with the fact that Coq is strongly normalizing (no infinite computations).
## Match
The *match* operator (or *pattern-matching*) is a case analysis, following the different possible constructors of an inductive type.
It is very similar to OCaml's match, except for little syntactic differences (`=>` in "branches", final keyword `end`).
```coq
match ... with
| C₁ x₁₁ ... x₁ₚ => ...
| ...
| Cₙ xₙ₁ ... xₙₖ => ...
end
```
The *head* of a match (what is between `match` and `with`) should be of the right inductive type, the one corresponding to constructors `C₁` ... `Cₙ`.
Usually, the *branches* (parts after `=>`) contains codes that have all the same type. We'll see later that this is not mandatory (see session on *dependent types*).
Computation and match : when the head of a match starts with a inductive constructor `Ci`, a *iota-reduction* is possible. It replaces the whole match with just the branch corresponding to constructor `Ci`, and also replaces all variables `xi₁`...`xiₚ` by concrete arguments found in match head after ̀Ci`.
Example:
```coq
Compute
match S (S O) with
| O => O
| S x => x
end.
```
This will reduce to `S O` (i.e. number 1 with nice pretty-printing). This computation is actually the definition of `pred` (natural number predecessor) applied to `S (S O)` i.e. number 2.
## Fix
The `Fixpoint` construction allows to create recursive functions in Coq. Beware, as mentionned earlier, some recursive functions are rejected by Coq, which only accepts *structurally decreasing recursive functions*.
The keyword `Fixpoint` is to be used in replacement of `Definition`, see examples below or in TD2.
Actually, there is a more primitive notion called `fix`, allowing to define an *internal* recursive function, at any place of a code. And `Fixpoint` is just a `Definition` followed by a `fix`. More on that later, but anyway, favor `Fixpoint` over `fix` when possible, it's way more convenient.
A `Fixpoint` or `fix` defines necessarily a function, with at least one (inductive) argument which is distinguished for a special role : the *decreasing argument* or *guard*. Before accepting this function, Coq checks that each recursive call is made on a syntactic *strict subterm* of this special argument. Roughly this means any subpart of it obtained via a `match` on this argument (and no re-construction afterwards). Nowadays, Coq determines automatically which argument may serve as guard, but you can still specify it manually (syntax `{struct n}`).
Computation of a `Fixpoint` or `fix` : when the guard argument of a fixpoint starts with an inductive constructor `Ci`, a reduction may occur (it is also called *iota-réduction*, just as for `match`). This reduction replaces the whole fixpoint with its body (what is after the `:=`), while changing as well in the body the name of the recursive function by the whole fixpoint (for preparing forthcoming iterations).
## Some usual inductive types
### nat : natural numbers represented as Peano integers
```coq
Print nat.
```
### Binary representation of numbers
```coq
Require Import ZArith.
Print positive.
Print N.
Print Z.
```
Nota bene : the "detour" by a specific type `positive` for strictly positive numbers allows to ensure that these representations are canonical, both for `N` and for `Z`. In particular, there is only one encoding of zero in each of these types (`N0` in type `N`, `Z0` in type `Z`).
### Coq pairs
```coq
Print prod.
Definition fst {A B} (p:A*B) := match p with
| (a,b) => a
end.
Definition fst' {A B} (p:A*B) :=
let '(a,b) := p in a.
```
### A first example of dependent type
```coq
Inductive unit : Type := tt : unit.
Fixpoint pow n : Type :=
match n with
| 0 => unit
| S n => (nat * (pow n))%type
end.
```
### The option type
```coq
Print option.
```
### The list type
```coq
Print list.
Require Import List.
Import ListNotations.
Check (3 :: 4 :: []).
Fixpoint length {A} (l : list A) :=
match l with
| [] => 0
| x :: l => S (length l)
end.
```
### Trees in Coq
No predefined type of trees in Coq (unlike `list`, `option`, etc). Indeed, there are zillions of possible variants, depending on your precise need. Hence each user will have to define its own (which is not so difficult). For instance here is a version with nothing at leaves and a natural number on nodes.
```ocaml
Inductive tree :=
| leaf
| node : nat -> tree -> tree -> tree.
```
Programmation Fonctionnelle en Coq (séance 2)
=============================================
**M2 LMFI**
## Contraintes d'univers
En complément de la séance 1 : Coq rejète certains usages des univers menant à des cycles de typage, qui mettent en danger la cohérence de la logique. La raison en est similaire au paradoxe de Russel, on parle ici de [paradoxe de Hurkens](https://coq.inria.fr/library/Coq.Logic.Hurkens.html) en théorie des types.
Voir [corrections/td1.v](corrections/td1.v) pour un exemple de *universe inconsistency* lors du `church_minus` (prolongement de l'exo 3): on voudrait que le type `church` puisse servir en tant que `X` dans le `forall X, (X->X)->(X->X)` qu'est `church` lui-même. Mais si `X` est dans un certain `Type_i`, alors `church` ne peut être qu'au niveau `Type_(i+1)` ou plus (faites ce typage vous-même!). Et donc on ne peut pas former l'application `church church` si les niveaux d'univers sont figés lors de la définition de `church`. Solution ici avec un Coq moderne : activer le *polymorphisme d'univers*, qui déterminera les niveaux d'univers de chaque instance de `church` à l'utilisation, et non à la définition. Cela aide grandement en pratique (mais pas toujours).
## Récursion générale et cohérence logique
Coq est cohérent tant qu'il est impossible de former une preuve *close* de `False`. Ici *close* signifie sans variables ni axiomes dans l'environnement. Sans même savoir comment ̀False` est défini, une récursivité générale nous permettrait d'avoir une telle preuve. Rappel: en Coq il n'y a pas de différence syntaxique entre une preuve et un programme.
```coq
Fixpoint loop (n:nat) : False := loop n
Definition boom : False := loop 0.
```
Evidemment une telle définition est rejeté par Coq. Voici l'équivalent en `OCaml` (ou il n'y a pas de question de cohérence logique):
```ocaml
let rec loop (n:int) : 'a = loop n
let any : 'a = loop 0 (* typage ok, par contre ça boucle à l'exécution *)
```
De même Coq repose de manière cruciale sur le fait qu'un terme clôt d'un type inductif va se réduire vers un des constructeurs de ce type, suivi du nombre d'arguments qui va bien. Ceci permet de montrer des propriétés du genre : tout booléen est égal à `true` ou bien à `false`, ou encore que tout entier `nat` est soit zéro, soit un successeur.
Là encore une récursivité générale briserait cette propriété. Par exemple:
```coq
Fixpoint flipflop (b:bool) := negb (flipflop b).
Definition alien : flipflop true.
```
Si `flipflop` était accepté, on aurait l'équation `flipflop true = negb (flipflop true)`, et donc `alien = negb alien`. Cet `alien` ne pourrait donc être ni `true` ni `false`.
## Types inductifs
En général, la syntaxe d'un type inductif est de la forme:
```coq
Inductive t :=
| C₁ : A₁₁ -> ... -> A₁ₚ -> t
| ...
| Cₙ : Aₙ₁ -> ... -> Aₙₖ -> t
```
Les `Cᵢ` sont les *constructeurs* du type `t`, ils peuvent attendre des arguments (ou pas), mais ont toujours `t` comme type de sortie.
En fait, `t` lui-même peut avoir des arguments, ce qui en fait un *schéma de type inductif*, on parle aussi de *prédicat inductif*. On verra des exemples par la suite.
## Condition de positivité
Certains inductifs ne sont pas acceptés par Coq, il s'agit encore d'une contrainte lié à la cohérence logique. Grosso modo, le type de l'inductif en cours de définition ne peut pas apparaître en argument d'un argument d'un constructeur de ce type. Cette condition est nommé *stricte positivité*.
Illustration du risque, en OCaml:
```ocaml
(* Primo, version "lambda-calcul" *)
type lam = Fun : (lam -> lam) -> lam
let identity = Fun (fun t -> t)
let app (Fun f) g = f g
let delta = Fun (fun x -> app x x)
let dd = app delta delta (* evaluation infinie, sans let rec ! *)
(* Secondo, une version produisant du 'a (donc possiblement False en Coq) *)
type 'a poly = Poly of ('a poly -> 'a)
let app (Poly f) g = f g
let delta = Poly (fun x -> app x x)
let dd : 'a = app delta delta
```
## Match
Le *match* (ou *pattern-matching*) est une analyse de cas, en suivant les constructeurs d'un type inductif.
A part de petites différences syntaxique (`=>` et mot-clé `end`), il se comporte de manière très similaire au `match` d'OCaml.
```coq
match ... with
| C₁ x₁₁ ... x₁ₚ => ...
| ...
| Cₙ xₙ₁ ... xₙₖ => ...
end
```
La *tête* du match (ce qu'il y a entre `match` et `with`) doit être du bon type inductif, celui correspondant aux constructeurs `C₁` ... `Cₙ`.
Habituellement, les *branches* (les portions après `=>`) contiennent du code d'un même type. On verra par la suite que ceci n'est pas obligatoire (cf. la séance sur les types *dépendants*).
Réduction d'un match : lorsque la tête d'un match commençe par un constructeur inductif `Ci`, une *iota-réduction* est possible, elle remplace alors tout le match par la branche correspondante au constructeur `Ci`, en replaçant dedans les variables `xi₁`...`xiₚ` par les arguments concrets du constructeur en tête de match.
## Fix
La construction `Fixpoint` va permettre de créer des fonctions récursives en Coq. Attention, comme mentionné auparavant, certaines fonctions récursives seront rejetées par Coq, qui ne va accepter que des *fonctions récursives structurellement décroissantes*.
Le mot-clé `Fixpoint` s'emploie à la place du mot-clé `Definition`, voir les exemples plus bas (ou dans les TD).
Il est également possible de définir une fonction récursive interne, à tout endroit d'un code, via le mot-clé `fix` (exemples la semaine prochaine). En fait, `Fixpoint` n'est pas une construction primitive de Coq, c'est un `Definition` suivi d'un `fix`.
Un `Fixpoint` ou `fix` définit obligatoirement une fonction, un argument de cette fonction joue un rôle particulier, on parle d'argument de décroissance (ou de *garde*). Avant d'accepter cette fonction récursive, Coq vérifie que chaque appel récursif se fait sur un sous-terme strict de cet argument (c'est-à-dire quelque-chose sortant d'un match sur cet argument). Par défaut, Coq cherche automatiquement quelque argument peut jouer ce rôle de garde, mais on peut le spécifier manuellement (syntaxe `{struct n}`).
Réduction d'un `Fixpoint` ou `fix` : lorsque l'argument de garde d'un fix commençe par un constructeur inductif `Ci`, une réduction est possible (on parle aussi de *iota-réduction*). On remplace alors tout le fix par son corps (ce qui suit le `:=`), en changeant dedans le nom de la fonction récursive par le fix de départ (pour permettre des itérations ultérieures).
## Quelques types inductifs usuels
### Les entiers naturels en représentation de Peano
```coq
Print nat.
```
### Représentation binaire des entiers
```coq
Require Import ZArith.
Print N.
Print positive.
Print Z.
```
Note : passer par un type des entiers strictement positifs permet d'assurer l'unicité de la représentation, aussi bien pour `N` que pour `Z`. En particulier il y a un seul codage de zéro (`N0` dans le type `N`, `Z0` dans le type `Z`).
### Paires Coq
```coq
Print prod.
Definition fst {A B} (p:A*B) := match p with
| (a,b) => a
end.
Definition fst' {A B} (p:A*B) :=
let '(a,b) := p in a.
```
### Un premier exemple de type dépendant
```coq
Inductive unit : Type := tt : unit.
Fixpoint pow n : Type :=
match n with
| 0 => unit
| S n => (nat * (pow n))%type
end.
```
### Le type option
```coq
Print option.
```
### Le type des listes
```coq
Print list.
Require Import List.
Import ListNotations.
Check (3 :: 4 :: []).
Fixpoint length {A} (l : list A) :=
match l with
| [] => 0
| x :: l => S (length l)
end.
```
### Arbres en Coq
Contrairement à ce qui précède, ceci n'est pas un type prédéfini en Coq. En effet il y a tellement de types d'arbres différents selon les besoins que c'est à l'utilisateur de définir le sien. Par exemple, voici une version avec rien aux feuilles et une donnée entière aux noeuds.
```ocaml
Inductive tree :=
| leaf
| node : nat -> tree -> tree -> tree.
```
Functional Programming in Coq (session 3)
=========================================
**M2 LMFI**
## Advanced Inductive Types
#### Ordinals
We can encode in Coq (some) ordinals, via the following type :
```coq
Inductive ord :=
| zero : ord
| succ : ord -> ord
| lim : (nat->ord) -> ord.
```
Note that this inductive type does satisfy the strict positivity constraint: constructor `lim` has an argument of type `nat->ord`, where `ord` appears indeed on the right. Having instead `lim:(ord->nat)->ord` would be refused by Coq.
We can plunge in this type the usual natural numbers of type `nat`.
For instance via a mixte addition `add : ord -> nat -> ord` :
```coq
Fixpoint add a n :=
match n with
| 0 => a
| S n => succ (add a n)
end.
Definition nat2ord n := add zero n.
```
Now, we could use constructor `lim` and this `add` function to go beyond the usual numbers.
```coq
Definition omega := lim (add zero).
Definition deuxomega := lim (add omega).
Fixpoint nomega n :=
match n with
| 0 => zero
| S n => lim (add (nomega n))
end.
Definition omegadeux := lim nomega.
```
Be careful, the standard equality of Coq is not very meaningful on these ordinals, since it is purely syntactic. For instance `add zero` and `add (succ zero)` are two different sequences (numbers starting at 0 vs. numbers starting at 1). So Coq will allow proving that `lim (add zero) <> lim (add (succ zero))` (where `<>` is the negation of the logical equality `=`). But we usually consider the limits of these two sequences to be two possible descriptions of `omega`, the first infinite ordinal. We would then have to define and use a specific equality on `ord`, actually an equivalence relation (we also call that a *setoid equality*).
#### Trees of variable arity
Let's encode a type of trees made of nodes having a natural number on them, and then an arbitrary number of subtrees, not just two like last week's `tree`.