• Aucun résultat trouvé

Fonctionnelles et polymorphisme

6.2 Types sommes ´ elabor´ es

Un autre exemple classique de type somme est la mod´elisation des peintures. On suppose que les peintures sont d´ecrites soit par un nom explicite, soit par un simple num´ero de r´ef´erence, soit par un m´elange d’autres peintures. Nous envisagerons succes- sivement ces trois cas et construirons donc le type peinture par raffinements successifs, en trois ´etapes.

´

Enum´erations

On consid`ere d’abord les peintures explicitement nomm´ees, en supposant qu’il en existe trois : le Bleu, le Blanc et le Rouge. Le type peinture comporte donc trois cas : c’est un type somme. Ces cas ne sont plus des valeurs de types diff´erents comme pour les polynˆomes, mais simplement trois constantes. On les mod´elise par trois constructeurs sans arguments, donc sans partie of dans la d´efinition :

# type peinture = | Bleu | Blanc | Rouge;;

Le type peinture est d´efini.

Les trois constructeurs sont maintenant trois nouvelles constantes du langage Caml, de type peinture.

# let p = Bleu;; p : peinture = Bleu

Tout naturellement, le filtrage s’applique aussi `a ce nouveau type :

# let est_blanche = function | Blanc -> true

| _ -> false;;

est_blanche : peinture -> bool = <fun> # est_blanche p;;

- : bool = false

Ces types somme ne comportant que des constantes sont appel´es types ´enum´er´es. Vous en connaissez d´ej`a : par exemple, le type bool est un type somme ´enum´er´e `a deux constantes, true et false.

Types `a constructeurs non constants

Nous supposons maintenant qu’il existe dans l’ensemble de toutes les peintures des teintes qui n’ont pas de nom, mais seulement un num´ero de r´ef´erence. Nous ´etendons donc le type peinture avec un nouveau constructeur qui prenne en compte ce cas. Il s’agit maintenant d’un constructeur ayant un argument : le num´ero de r´ef´erence. Appelons ce constructeur Num´ero. Par exemple, Num´ero 14 mod´elisera la peinture de r´ef´erence num´ero 14. Nous d´efinissons donc le nouveau type des peintures comme :

# type peinture = | Bleu | Blanc | Rouge

| Num´ero of int;; Le type peinture est d´efini.

Types r´ecursifs

La prochaine ´etape est la description des m´elanges de peintures. Il existe maintenant des peintures qui sont simplement des m´elanges de deux autres peintures (en propor- tions ´egales) et qu’on identifie par les peintures qui les composent. Nous introduisons donc un nouveau constructeur M´elange avec pour argument un couple de peintures. Notre type devient :

# type peinture = | Bleu | Blanc | Rouge

| Num´ero of int

| M´elange of peinture * peinture;; Le type peinture est d´efini.

# let m´el1 = M´elange (Bleu, Blanc);; m´el1 : peinture = M´elange (Bleu, Blanc) # let m´el2 = M´elange (Num´ero 0, Rouge);; m´el2 : peinture = M´elange (Num´ero 0, Rouge)

Remarquez que le type peinture est devenu r´ecursif, puisqu’il intervient dans sa propre d´efinition. Ainsi, on peut m´elanger n’importe quelles peintures et en particulier faire des m´elanges de plus de deux peintures.

# let m´el3 = M´elange (m´el1,m´el2);; m´el3 : peinture =

M´elange (M´elange (Bleu, Blanc), M´elange (Num´ero 0, Rouge))

Le filtrage sur le type peinture ne pose pas de probl`emes :

# let rec contient_du_bleu = function | Bleu -> true

| M´elange (p1,p2) -> contient_du_bleu p1 || contient_du_bleu p2 | _ -> false;;

contient_du_bleu : peinture -> bool = <fun> # contient_du_bleu m´el3;;

Types sommes ´elabor´es 115 La d´efinition du type peinture, quoique r´ecursive, conserve tout de mˆeme un sens, parce qu’il existe des cas de base pour arrˆeter la r´ecursion. C’est tout `a fait analogue aux d´efinitions de fonctions r´ecursives qui pr´esentent des cas d’arrˆet simples. Les cas de base du type, comme par exemple les constructeurs sans arguments, correspondent souvent `a des cas de base des fonctions r´ecursives sur ce type.

Les cartes

On mod´elise tr`es ais´ement un jeu de cartes en utilisant les types somme. Les couleurs forment un type ´enum´er´e :

# type couleur = | Tr`efle | Carreau | Coeur | Pique;; Le type couleur est d´efini.

et les cartes un type somme `a plusieurs possibilit´es, selon les valeurs faciales des cartes :

# type carte = | As of couleur | Roi of couleur | Dame of couleur | Valet of couleur

| Petite_carte of int * couleur;; Le type carte est d´efini.

Dans cette d´efinition, nous avons choisi de regrouper toutes les cartes qui ne sont pas des figures sous la mˆeme d´enomination : Petite_carte. On aurait pu aussi continuer l’´enum´eration avec des constructeurs Dix, Neuf, Huit, etc.

Pour illustrer le filtrage sur les types somme, nous d´efinissons la valeur d’une carte `

a la « belote ». Cette valeur d´epend d’une couleur particuli`ere, l’atout, choisie par les joueurs `a chaque tour. Les cartes dont la valeur change sont le valet et le neuf : le neuf compte d’ordinaire pour 0, mais vaut 14 quand il est de la couleur de l’atout, et le valet d’atout vaut 20 au lieu de 2 d’ordinaire. D’autre part, les dix valent 10 points et les autres petites cartes 0.

# let valeur_d’une_carte couleur_d’atout = function | As _ -> 11

| Roi _ -> 4 | Dame _ -> 3

| Valet c -> if c = couleur_d’atout then 20 else 2 | Petite_carte (10, _) -> 10

| Petite_carte (9, c) -> if c = couleur_d’atout then 14 else 0 | _ -> 0;;

valeur_d’une_carte : couleur -> carte -> int = <fun>

Remarquez que la structure du filtrage de la fonction valeur_d’une_carte est tr`es similaire `a la d´efinition du type carte. C’est un m´ecanisme fr´equent en Caml : pour d´efinir une fonction sur un type somme, on se guide souvent sur la d´efinition du type qui donne le squelette du filtrage `a utiliser. On le compl`ete alors pour envisager les cas particuliers, comme ici les cas du 10 et du 9.

Cela termine les exemples de types somme. Nous donnons maintenant une pr´esentation plus g´en´erale du concept.