2- Types récursifs
I. Définition inductive d'un ensemble
Idée : définir un ensemble d'objets "par récurrence".
Définition : ensemble inductif
Un ensemble inductif
- un ensemble
de cas de base ; - un ensemble
de constructeurs, qui sont des fonctions où .
On pose :
Alors, on a
En français : on peut appliquer les constructeurs autant de fois que nécessaire (en se limitant à un nombre fini de fois) à partir des cas de base, pour obtenir tous les éléments de
Par exemple :
- on peut définir les listes d'entiers inductivement comme :
- soit la liste vide
[]; - soit
x::q, oùxest un entier etqune liste ;
- soit la liste vide
- on peut définir les arbres comme :
- soit une feuille
F; - soit un nœud, composé de deux arbres ou plus !
- soit une feuille
II. L'équivalent OCaml : les types récursifs
a) Types énumération
On peut écrire des types énumération en OCaml :
Loading editor...
type classe =
| MPSI_1
| MPSI_2
| MP_1
| MP_2
| MP_ET;;Une valeur de type classe peut alors prendre une des 5 valeurs définies (et rien d'autre !). Par exemple :
Loading editor...
let ma_classe: classe = MPSI_1;;
On peut également stocker des données arbitraires dans une des options :
Loading editor...
type classe =
| MPSI_1
| MPSI_2
| MP_1
| MP_2
| MP_ET
| Autre of string;;
let ma_classe: classe = Autre "BCPST";;La construction match est alors très utile, car elle permet de traiter séparément chaque cas du type énumération.
Loading editor...
let nb_eleves (c: classe): int = match c with
| MPSI_1 -> 49
| MPSI_2 -> 43
| MP_1 -> 38
| MP_2 -> 36
| MP_ET -> 40
| Autre nom -> failwith ("classe inconnue : " ^ nom);;Loading editor...
nb_eleves MP_1;; nb_eleves MPSI_2;;
b) Types récursifs
On peut également faire des types récursifs, c'est-à-dire utiliser le type classe dans sa propre définition !
Bien sûr, il faut que certains variants n'utilisent pas de type récursif, pour qu'on puisse "s'arrêter".
Loading editor...
type classe = MP | MPSI | PCSI | PC | Autre of string | DoubleNiveau of classe * classe;; let classe4 = DoubleNiveau (MP, PC);; let classe5 = DoubleNiveau (DoubleNiveau (MP, PC), Autre "MPI");;
III. Petit point sur les listes
En OCaml, on pourrait définir nous-mêmes un type de liste :
Loading editor...
type liste = Vide | El of int * liste;;
Par exemple, la liste [1; 2; 3] s'écrit alors :
Loading editor...
let l : liste = El (1, El (2, El (3, Vide)));;
(* la longueur d'une liste, par récurrence sur sa structure *)
let rec longueur (l: liste): int = match l with
| Vide -> 0
| El (_, q) -> 1 + longueur q;;
longueur l;;Exercices
Exercice 1
Avec le type liste de la partie III, écrire une fonction somme : liste -> int, puis une fonction vers_liste : liste -> int list qui convertit une liste en liste OCaml.
Loading editor...
let rec somme (l : liste) : int = match l with
| Vide -> 0
| El (x, q) -> x + somme q;;
let rec vers_liste (l : liste) : int list = match l with
| Vide -> []
| El (x, q) -> x :: vers_liste q;;Exercice 2
Définir un type carte pour représenter une carte à jouer : une couleur (pique, cœur, carreau, trèfle) et une valeur (un entier de 2 à 10, valet, dame, roi ou as). Écrire une fonction points : carte -> int qui donne 11 points pour un as, 10 pour une figure, et la valeur sinon.
Loading editor...
type couleur = Pique | Coeur | Carreau | Trefle;;
type valeur = Nombre of int | Valet | Dame | Roi | As;;
type carte = valeur * couleur;;
let points ((v, _) : carte) : int = match v with
| As -> 11
| Valet | Dame | Roi -> 10
| Nombre n -> n;;
points (Dame, Coeur);;Exercice 3
Avec le type classe récursif de la partie II.b, écrire une fonction nb_niveaux : classe -> int qui compte le nombre de classes "simples" dans une classe : nb_niveaux classe5 doit valoir 3.
Loading editor...
let rec nb_niveaux (c : classe) : int = match c with
| DoubleNiveau (c1, c2) -> nb_niveaux c1 + nb_niveaux c2
| _ -> 1;;