• Aucun résultat trouvé

4.3 Diagonalisation

Pour pouvoir construire une clause de retour, il faut savoir : — extraire le squelette d’index, mais aussi,

— abstraire les variables libres dont le type interfère avec l’objet filtré ou ses index. Conserver les liens avec les types des variables libres introduit les coupures entrelacées. Spécialiser la clause de retour suivant le squelette d’index élimine les branches impossibles. Cela demande du filtrage dans le diagonaliseur. Il y a donc du filtrage dans la clause de re- tour du filtrage. Cependant le filtrage dans la clause de retour a lieu sur le type d’un index du terme filtré. Il a donc lieu sur un inductif défini strictement plus tôt dans le contexte glo- bal. La terminaison est assurée, la lisibilité du résultat par contre ne l’est pas. Nos exemples explicatifs sont incrémentaux pour ne pas noyer le lecteur.

Commençons par illustrer l’utilisation d’un squelette d’index et la reconnaissance de bran- ches impossibles. Fournir un habitant du typeFalseest et doit rester impossible. Il est pour- tant possible d’écrire une preuve de ∀(H : even1),False(pourevendéfini figure 1.12) par filtrage surH.

La clause de retour de l’élimination d’un terme de type even u a la forme λ(n : nat) (e : evenn) ⇒P n e. Les constructeursSetOsont des constantes injectives. Le diagona- liseur de la figure 4.1 permet en filtrant surnde montrer que P1 _ renvoieFalse comme attendu mais que P(S (S m)) (even_SSm) et P O even_Odemandent des termes de type

Truefaciles à construire.

Definitiondiag_even1(n : nat) (e : evenn) :Set :=

casen predicateλ(_ : nat) ⇒Set of

|O:True

|S:λ(m : nat) ⇒casem predicateλ(_ : nat) ⇒Set of

|O:False

|S:λ(_ : nat) ⇒True

end end.

Definitioneven1(H : even(S O)) :False :=

caseH

predicateλ(n : nat) (e : evenn) ⇒diag_even1n e of

|even_O:I

|even_SS:λ(m : nat) ⇒I

end.

Figure 4.1 – Diagonaliseur poureven1

La section précédente a illustré deux techniques : généraliser le type attendu en retour de l’analyse de cas et incorporer aux clauses de retour la séparation des constructeurs. Mettons maintenant en œuvre pleinement ces constructions. Dans l’exemple précédent (x=Ca b→P

a b) les variablesa bsont devenuesa’ b’à l’intérieur ducase. Plus généralement, les variables

qui apparaissent en feuilles du squelette d’index sont substituées autant que possible par les variables issues de l’analyse de cas. Une telle substitution n’est pas une opération sûre : si la

variable substituée apparaît dans les paramètres de l’inductif ou apparaît à plusieurs feuilles, le terme construit est mal typé. La fin de ce chapitre détaille notre heuristique (section 4.5).

Ecrire un terme de type ∀(n : nat) (e: even(S (Sn))),evennpar analyse de cas sur

emet en application ce principe. Le caseven_Oest une branche impossible carO,S(S_) . L’argumentmdeeven_SSest utilisé lui dans le type attendu. Le prédicat de diagonalisation est

Definitiondiag_SS (n : nat) (e : even(S (Sn))) :Set :=

casen predicateλ(_ : nat) ⇒Set of

|O:True

|S:λ(x : nat) ⇒casex predicateλ(_ : nat) ⇒Set of

|O:True|S:λ(m : nat) ⇒evenm end

end.

Figure 4.2 – Diagonaliseur pour inverserevenSS

Nous n’utilisons ici que la feuille du squelette d’index dont le type n’est pas dépendant. Dès qu’est utilisée une variable dont le type évolue au cours du raffinement du squelette d’index, une coupure entrelacée est nécessaire. En particulier, le type de la variable représentant la généralisation du terme filtré doit se raffiner au fur et à mesure que les index du terme filtré sont raffinés.

Afin d’illustrer cette affirmation, nous introduisons une nouvelle structure de données dépendante. La figure 4.3 défini la famille des ensembles finis. Le typeFinnreprésente l’en- semble [|1 .. n|]. Le constructeurF1 mreprésente le premier élément d’un ensemble à Sm éléments alors queFSm freprésente le (k + 1)-ième élément d’un ensemble àSméléments sifreprésente le k-ième élément d’un ensemble àméléments. Par exemple,FinOest vide,

Fin(S(S O)) contientF1(S O) etFS(S O) (F1 O), etc.

InductiveFin :nat→Set := |F1 :∀(n : nat),Fin(Sn)

|FS :∀(n : nat),FinnFin(Sn).

Figure 4.3 – Famille inductive des ensembles de taille fixée

Avec cette définition, comment raisonner par cas sur un élément quelconque d’un en- semble non vide ? Supposons par exemple queta le type Fin(Sn) pour nfixé et que l’on souhaite raisonner par cas dessus. Le but est alors d’écrire un terme de type ∀(n : nat) (f : Fin(Sn)),Pn f. Son diagonaliseur va nécessairement débuter par les abstractions is- sues de la définition de la famille inductive : λ(k : nat) (f’ : Fink) ⇒ . . .. il faut ensuite filtrer surk pour retrouver qu’il est non nul sans perdre le fait que f’a k éléments. La va- riablef’est dans le contexte, une coupure entrelacée la remet dans la conclusion. La figure 4.4 montre le résultat.

Les diagonaliseurs réalisent pour l’instant des filtrages surnat, un inductif non dépendant. Les diagonaliseurs des analyses de cas du diagonaliseur étaient implicites car simples. Dans le cas général, il faut de nouveau prendre en considération dans le diagonaliseur les branches

4.3 Diagonalisation

Definitiondiag_finS (k : nat) (f’ : Fink) :Set :=

casek predicateλ(k’ : nat) ⇒Fink’→Set of |O:λ(fo : FinO) ⇒True

|S:λ(k’ : nat) (fs : Fin(Sk’)) ⇒P k’ fs

endf’.

λ(n : nat) (f : Finn) ⇒casef predicatediag_finS of

|F1:λ(m : nat) ⇒. . . : P m (F1m)

|FS:λ(m : nat) (f’ : Finm) ⇒. . . : P m (FSm f’)

end

Figure 4.4 – Diagonaliseur pour ensemble non vide

impossibles, généraliser suivant les index et le terme éliminé mais aussi prévenir les désyn- chronisations des types des variables du contexte avec ceux des arguments du constructeur dans la branches. Bref, bâtir récursivement nos diagonaliseurs.

Considérons par exemple l’élimination d’un prédicat (H :FLast (S n) (FSn f)) oùFLast

exprime la propriété d’être le dernier élément d’un ensemble non élémentaire (figure 4.5) pour conclurePn f H. Il faudra construire successivement trois diagonaliseurs.

InductiveFLast :∀(n : nat) (f : Finn),Set :=

|FL1 :FLast(S O) (F1 O)

|FLS :∀(n : nat) (f : Finn),FLastn f→FLast(Sn) (FSn f).

Figure 4.5 – Dernier élément d’un ensemble

Le prédicat de diagonalisation figure 4.7 débute par un filtrage sur l’entier. L’ensemble et le prédicat ne doivent pas être introduits afin de conserver les dépendances de type. Le prédicat (diag_Fin: ∀(k : nat) (f : Fin(Sk)) (H : Flast(Sk) f),Set) doit ensuite par filtrage sur

fêtre égal à P appliqué aux variables du dernier filtrage dans le casFSet àTruesinon. Pour conserver les correspondances de type alors qu’un constructeur apparaît dans le type def, l’élimination a pour clause de retour le diagonaliseurdiag_nat.

Ici il existe un diagonaliseur bien plus simple donné figure 4.8 qui économise l’analyse de cas sur les entiers vu qu’ils sont arguments de l’ensemble. Néanmoins, la présence de diagonaliseurs dans les diagonaliseurs est générique et absolument nécessaire en général.

Pour preuve, voici notre dernier exemple : l’inversion du prédicat d’égalité sur deux en- sembles de même taille défini figure 4.6. Il met en oeuvre tous les mécanismes expliqués. Cette fois, tous sont nécessaires. Le résultat est indigeste, il est heureux que la section 4.7 donne l’algorithme formel pour le générer afin que plus jamais il ne soit écrit manuellement.

InductiveFinEq :∀(n : nat),Finn→Finn→Set := |F1Eq :∀(n : nat),FinEq(Sn) (F1n) (F1n)

|FSEq :∀(n : nat) (f1 f2 : Finn),FinEqn f1 f2→FinEq(Sn) (FSn f1) (FSn f2).

Definitiondiag_FLS(m : nat) :∀(f : Finm) (H : FLastm f),Set :=

casem predicateλ(m’ : nat) ⇒ ∀(f : Finm’) (H : FLastm’ f),Set of

|O:λ(f’ : FinO) (_ : FLastOf’) ⇒True

|S:λ(k : nat) ⇒diag_Fink

end.

where

Definitiondiag_Fin (k : nat) (f : Fin(Sk)) :∀(H : FLast(Sk) f),Set :=

casef predicatediag_nat of |FS:λ(j : nat) (f0 : Finj) ⇒

λ(H : FLast (Sj) (FSj f0)) ⇒P j f0 H

|F1:λ(j : nat) ⇒ λ(_ : FLast(Sj) (F1j)) ⇒True

end.

and

Definitiondiag_nat (i : nat) :∀(f : Fini),Set :=

casei predicateλ(i’ : nat) ⇒ ∀(f : Fini’),Set of

|O:λ(_ : FinO) ⇒True

|S:λ(j : nat) ⇒ λ(f’ : Fin(Sj)) ⇒ ∀(H : FLast(Sj) f’),Set

end.

Figure 4.7 – Diagonaliseur pour ∀(H : FLast(Sn) (FSn f)),P n f H

λ(m : nat) (f : Finm) ⇒

casef predicateλ(i : nat) (f’ : Fini) ⇒FLasti f’→Set of |F1:λ(i : nat) (H : FLast (Si) (F1i)) ⇒True

|FS:λ(i : nat) (f0 : Fini) (H : FLast(Si) (FSi f0)) ⇒P i f0

end

4.3 Diagonalisation

Definitiondiag_x1 (x1 : nat) :Finx1→Set := casex1 predicateλ(n2 : nat) ⇒Finn2Set of

|O:λ(_ : Fin O) ⇒True

|S:λ(x0 : nat) ⇒ λ(f1’ : Fin(Sx0)) ⇒ ∀(f2 : Fin(Sx0)),FinEq(Sx0)f1’ f2Set

end.

Definitiondiag_x2 (x2 : nat) :Finx2→Set := casex2 predicateλ(n3 : nat) ⇒Finn3Set of

|O:λ(_ : FinO) ⇒True

|S:λ(x0 : nat) ⇒ λ(f2’ : Fin(Sx0)) ⇒ ∀(f1’’ : Finx0),

FinEq(Sx0) (FSx0 f1’’)f2’→Set

end.

Definitiondiag_H (n0 : nat) :∀(f1 f2 : Finn),FinEqn f1 f2→Set := casen0 predicateλ(n1 : nat) ⇒ ∀(f4 f5 : Finn1),FinEqn1 f4 f5Set of

|O:λ(f4 f5 : FinO) (_ : FinEqO f4 f5) ⇒True

|S:λ(x : nat) ⇒ λ(f4 : Fin(S x)) ⇒

casef4 predicatediag_x1 of

|F1:λ(n1 : nat) ⇒ λ(f5 : Fin(Sn1)) (_ : FinEq(Sn1) (F1n1)f5) ⇒True

|FS:λ(n1 : nat) (f5 : Fin(S n1)) ⇒ λ(f6 : Fin(S n1)) ⇒ (casef6 predicatediag_x2 of

|F1:λ(n2 : nat) ⇒ λ(f7 : Finn2)

(_ : FinEq(Sn2) (FSn2 f7) (F1n2)) ⇒True

|FS:λ(n2 : nat) (f7 : Finn2) ⇒ λ(f8 : Finn2) (_ : FinEq(Sn2) (FSn2 f8) (FSn2 f7)) ⇒

FinEqn2 f8 f7

endf5) end end.

Definitioninvert_H(n : nat) (f1 f2 : Finn)

(H : FinEq(Sn) (FSn f1) (FSn f2)) :FinEqn f1 f2 :=

caseH predicateλ(n0 : nat) (f f0 : Finn0) (H’ : FinEqn0 f f0) ⇒diag_nf f0 H’ of

|F1Eq:λ(_ : nat) ⇒I

|FSEq:λ(m : nat) (f’ f’’ : Finm) (H0 : FinEqm f’ f’’) ⇒H0

end.