Les définitions de nouveaux types en Caml

Contacter l'auteur Pierre.Weis@inria.fr

Fichier créé en décembre 1995.

On utilise les définitions de type pour modéliser des structures de données qui n'entrent pas facilement dans les structures de données de base prédéfinies en Caml. Une définition de type introduit toujours un nouveau type incompatible avec tous les types précédemment définis.

Les définitions de types sont toutes introduites par le mot-clé type. Les définitions de types sont récursives par défaut et peuvent être polymorphes (en ce cas le type défini possède des arguments (voir, ou)). Pour définir simultanément plusieurs types on sépare les définitions par le mot-clé and.

Table des matières:

Il existe trois espèces de types de données définissables en Caml:

Les types sommes

Un type somme est formé d'une liste de cas possible pour une valeur de ce type, chaque cas comporte un nom de cas, le ``constructeur'', et une (éventuelle) valeur associée (l'argument du constructeur).

Un cas dégénéré consiste à définir un type dont les constructeurs n'ont pas d'argument (constructeurs constants). On parle alors de type énuméré, type somme dont on enumère effectivement les constantes (le symbole ``|'' se lit ``ou''):

#type couleur = Bleu | Blanc | Rouge;;
Le type couleur est défini.
#Bleu;;
- : couleur = Bleu

Les noms Bleu Blanc et Rouge sont les constructeurs du type couleur.

Dans le cas général les constructeurs ont des arguments: à la définition du type somme on indique leur type après le mot-clef of.
Par exemple, on implémente les polynômes soit pleins (peu de zéros) soit creux (beaucoup de zéros) par la définition du type polynôme à deux constructeurs Creux et Plein:

#type polynôme = Creux of int list | Plein of int vect;;
Le type polynôme est défini.
#let nul = Creux [0];;
nul : polynôme = Creux [0]
#let un_plus_deux_x = Plein [|1; 2|];;
un_plus_deux_x : polynôme = Plein [|1; 2|]

Les constructeurs permettent de distinguer les cas par filtrage:

#let minus_pol = function
| Creux l -> Creux (map (function x -> - x) l)
| Plein v -> Plein (map_vect (function x -> - x) v);;
minus_pol : polynôme -> polynôme = <fun>
#minus_pol nul;;
- : polynôme = Creux [0]
#minus_pol un_plus_deux_x;;
- : polynôme = Plein [|-1; -2|]

Remarque: l'usage est d'écrire en majuscule la première lettre du nom d'un constructeur de valeur d'un type somme. Ainsi on choisit de nommer ``Creux'' plutôt que ``creux'' le constructeur des polynômes creux.

Pour un exemple de type somme polymorphe voir ici.

Les types enregistrement

Un type enregistrement est formé d'une liste de rubriques comportant un nom de rubrique (le label) et une valeur associée (la valeur du champ):

#type personne = {Nom : string; Age : int};;
Le type personne est défini.
#let x = {Nom = "toto"; Age = 7};;
x : personne = {Nom="toto"; Age=7}
#x.Nom;;
- : string = "toto"

Les rubriques d'un type enregistrement peuvent être déclarées mutables lors de la définition du type. On a alors le loisir de les modifier par la construction r.label <- nouvelle_valeur.
Par exemple le solde d'un compte en banque est modifiable alors que le numéro de ce compte est une donnée fixe:

#type compte = {Numéro : int; mutable Solde : float};;
Le type compte est défini.
#let compte_ref = ref 0;;
compte_ref : int ref = ref 0
#let crée_compte dépôt_initial =
 incr compte_ref;
 {Numéro = !compte_ref;
  Solde = dépôt_initial};;
crée_compte : float -> compte = <fun>
#let compte_dupont = crée_compte 500.0;;
compte_dupont : compte = {Numéro=1; Solde=500.0}
#let dépose somme compte =
 compte.Solde <- compte.Solde +. somme;;
dépose : float -> compte -> unit = <fun>
#dépose 100.0 compte_dupont;;
- : unit = ()
#compte_dupont;;
- : compte = {Numéro=1; Solde=600.0}

Pour comprendre la différence entre un champ modifiable et un champ non modifiable contenant une valeur mutable voir ici.

Types enregistrement polymorphes

Comme pour toutes les espèces de types Caml, on définit des types enregistrements polymorphes en listant les arguments du nouveau type.
Voici par exemple le type des cellules (ou arbres binaires) polymorphes et mutables:

 
#type ('a, 'b) cell = {mutable Car : 'a; mutable Cdr : 'b};;
Le type cell est défini.
#{Car = 1; Cdr = "ok"};;
- : (int, string) cell = {Car=1; Cdr="ok"}
#let rplaca cell val =
 cell.Car <- val;;
rplaca : ('a, 'b) cell -> 'a -> unit = <fun>

Types somme polymorphes

On peut aussi définir des types sommes polymorphes:

#type ('a, 'b) sexpr =
   Symbol of string
 | Cell of ('a, 'b) cell;;
#let nil = Symbol "";;
nil : ('a, 'b) sexpr = Symbol ""
#let cons v1 v2 = Cell {Car = v1; Cdr = v2};;
cons : 'a -> 'b -> ('a, 'b) sexpr = <fun>
#let l = cons 1 (cons 2 nil);;
l : (int, (int, ('_a, '_b) sexpr) sexpr) sexpr =
 Cell {Car=1; Cdr=Cell {Car=2; Cdr=Symbol ""}}

Les types abréviation

Un type abréviation définit un alias pour une expression de type:

#type compteur == int;;
Le type compteur est défini.
#let x = (1 : compteur);;
x : compteur = 1

Les valeurs d'un type abréviation peuvent être considérées comme du type abrégé:

#x + 1;;
- : int = 2

Les types abréviation servent dans les modules (pour définir un type exigé par l'interface du module) ou à des fins de documentation.


Page de présentation de Caml Dernière modification: vendredi 26 mars 2004
Copyright © 1995 - 2004, INRIA tous droits réservés.

Contacter l'auteur Pierre.Weis@inria.fr