@@ -5,15 +5,57 @@ Programmation Fonctionnelle en Coq (seance 3)
## Types inductifs avancés
Détails à venir
#### Ordinaux
On peut encoder en Coq (certains) ordinaux, via le type suivant.
```coq
Inductiveord:=
|zero:ord
|succ:ord->ord
|lim:(nat->ord)->
|lim:(nat->ord)->ord.
```
Noter que cet inductif satisfait bien la contrainte de strict positivité: `lim` a un argument de type `nat->ord`, où `ord` apparaît bien à droite. Par contre un `lim:(ord->nat)->ord` serait refusé par Coq.
On peut plonger dans ce type les entiers naturels `nat` habituels.
Par exemple via une addition mixte `add : ord -> nat -> ord` :
```coq
Fixpointaddan:=
matchnwith
|0=>a
|Sn=>succ(addan)
end.
Definitionnat2ordn:=addzeron.
```
Maintenant, on peut utiliser `lim` pour aller au delà des entiers usuels.
```coq
Definitionomega:=lim(addzero).
Definitiondeuxomega:=lim(addomega).
Fixpointnomegan:=
matchnwith
|0=>zero
|Sn=>lim(add(nomegan))
end.
Definitionomegadeux:=limnomega.
```
Attention, l'égalité standard de Coq n'est pas celle qu'on veut utiliser sur ces ordinaux. Ainsi `add zero` et `add (succ zero)` sont deux suites différentes (les entiers à partir de 0 vs. les entiers à partir de 1). Donc pour Coq on pourra prouver que `lim (add zero) <> lim (succ zero)`, alors qu'on considère normalement qu'il s'agit de deux descriptions possibles de `omega`. Il faudra alors utiliser une égalité particulière sur `ord`, en fait une relation d'équivalence (on parle aussi d'égalité sétoide).
#### Arbres d'arité variable
```coq
Inductivenarbre:=
|Node:listnarbre->narbre.
```
Plus besoin de constructeur "feuille", on utilise `Node []` à la place.
## Fix fix
La fonction d'Ackermann est-elle structurellement décroissante ?
...
...
@@ -22,10 +64,42 @@ La fonction d'Ackermann est-elle structurellement décroissante ?
-`ack (n+1) 0 = ack n 1`
-`ack (n+1) (m+1) = ack n (ack (n+1) m)`
Détails à venir
Non si on utilise un seul point-fixe, en effet ni `n` ni `m` (pris isolément) ne garantie une décroissance. Mais il existe une ruse (assez classique maintenant) consistant à mettre un `fix` interne dans notre `Fixpoint` :
```coq
Fixpointackn:=
matchnwith
|0=>S
|Sn=>
fixack_Snm:=
matchmwith
|0=>ackn1
|Sm=>ackn(ack_Snm)
end
end.
Computeack35.
```
## Principes d'induction
A chaque nouveau type inductif, `Coq` génère automatiquement des fonctions particulières nommées principes d'induction. Normalement, pour un type `foo`, on dispose alors d'une fonction `foo_rect`. Cette fonction suit la forme du type inductif pour proposer une récurrence adapté à ce type.
```coq
Checknat_rect.
Printnat_rect.
```
Exemples de programmation sur `nat` sans `Fixpoint` ni `match`, juste avec `nat_rect`:
```coq
Definitionpredn:nat:=nat_rect_0(funnh=>n)n.
Definitionaddnm:nat:=nat_rect_m(fun_h=>Sh)n.
```
Dans ces deux derniers cas, le "prédicat" donné à `nat_rect` (son premier argument `_`) est en fait `fun _ => nat`, ce qui signifie qu'on utilise `nat_rect` de manière non-dépendante.
## Pseudo principes d'induction
Exemple de `Pos.peano_rect`
Exemple de `Pos.peano_rect` : on détourne (manuellement) la récurrence (binaire) sur le type `positive` pour fabriquer une récurrence unaire.