Lycée Claude Fauriel MP2I
TRAVAUX PRATIQUES VII
Introduction à OCaml (2)
A Filtrage
Définition 1
Filtrage :
Rappel : la syntaxe basique du filtrage par motif (pattern matching en Anglais) est la suivante :
match expr with | filtre_1 -> expr2 | filtre_2 -> expr2 | ... .
On utilise le symbole _ pour désigner n’importe quel motif sans lui donner de nom.
Exemples :
1 let x = read_int () in match x with
2 | 0 -> print_string "tu as écrit 0"
3 | 1 -> print_string "tu as écrit 1"
4 | _ -> print_string "tu n'as écrit ni 0 ni 1"
OCaml
5 ;;
6
7 let exemple (n : int) = match n with
8 | m when m >= 0 -> "positif"
9 | m -> "negatif"
10 ;;
1. Quels sont les types des deux expressions ci-dessus ? Sont-elles critiquables ?
2. Que renvoie exemple 0 ?
3. En mathématiques, on définit la fonction 𝑠𝑖𝑛𝑐 par 𝑠𝑖𝑛𝑐(𝑥) = sin(𝑥)𝑥 si x est un réel différent de 0 et par 1 si x = 0.
À l’aide du filtrage par motif, écrire une fonction permettant de calculer cette fonction.
4. Corriger tous les défauts du programme suivant :
1 let carre_positif x = match x with
OCaml
2 | x when x < 0 -> 0
3 | x when x >= 0 -> x**2.
4 ;;
5. Filtrage sur les listes :
Écrire une fonction est_vide qui prend en argument une liste et renvoie true si la liste est vide et false
sinon.
6. Écrire une fonction test_longueur qui prend en argument une liste et renvoie true si la liste possède
exactement 2 ou 4 éléments et false sinon.
7. Écrire une fonction doublon qui prend en argument une liste et renvoie true si les deux premiers éléments
de la liste sont égaux et false sinon (y compris si la liste possède moins de deux éléments).
B Types
B.1 Types produits et N-uplets
Exemples :
1
TP VII. Introduction à OCaml (2)
1 let t = (1.5,"bonjour");; (* t est de type float * string *)
2 let (x,s) = t;; (* ce let destructurant permet de définir à la fois x et y, et d'accéder sans "
match" aux composants de t *)
OCaml
3
4 let (a,b) = (1,2);;
5 let u = (3,4);;
6 let f (x,y) = 2*x + y ;;
7 f (a,b);;
8 f u;;
8. Écrire une fonction qui prend en argument deux entiers x et y et renvoie le quotient et le reste de la division
euclidienne de x par y sous la forme d’un couple d’entiers.
B.2 Types Enregistrements
Enregistrements :
La syntaxe pour définir un type enregistrement est la suivante :
Définition 2
type enregistrement = {champ1 : type1; champs2 : type2; ...} .
Pour définir un élément de ce type, on déclare chacun de ces champs en suivant la syntaxe suivante :
let elem = {champ1 = val1; champ2 = val2; ...}
Et pour manipuler un élément de type, on accède à ses champs via : [Link] .
type complexe = {re : float; im : float};;
OCaml
1
2 let j = { re = -0.5; im = sqrt(3.)/.2.};;
3 print_float ([Link]);;
9. Entiers de Gauss : Un entier de Gauss est un nombre complexe dont la partie réelle et la partie imaginaire sont
entières.
a. (maths) On admet que l’ensemble des entiers de Gauss est stable par conjugaison, addition, multiplication. 1
b. Définir en OCaml un type enregistrement entierGauss ainsi qu’une constante correspondant au nombre
complexe i.
c. Définir les fonctions somme, produit et conjugaison sur les entiers de Gauss.
B.3 Types sommes
OCaml Définition 3 : Sommes
La syntaxe pour définir un type somme se fait via des constructeurs, qui commencent nécessairement par une
majuscule.
type montype = Cons1 (of type1) | Cons2 (of type2) | ...
1 type jour = Lundi | Mardi | Mercredi | Jeudi | Vendredi | Samedi | Dimanche;;
2 let jour_prefere = Samedi;;
3 type nombre_quelconque = Entier of int | Flottant of float | Pi ;;
4 let x = Flottant(2.5);;
5 let nq_of_int n = Entier n;;
10. Écrire une fonction de type jour -> int qui prend en argument un jour et renvoie sa position dans la semaine
(entre 1 et 7) (en utilisant un filtrage).
11. Pokemon : On considère le type somme suivant (qui ne contient que des constantes) :
OCaml
1 type poketype = Plante | Feu | Eau
Définir un type enregistrement pokemon contenant un champ nom de type string , un champ pv de type
int (les points de vie) et un champ ptype contenant un poketype.
1. Vous pouvez le prouver plus tard chez vous pour vous entraîner si vous voulez.
2
TP VII. Introduction à OCaml (2)
12. Utilisons notre type pour représenter des pokemons ! Définissez Dracaufeu : un pokemon de type Feu 2 qui possède
78pv.
13. Définissez Tiplouf : un pokemon de type Eau qui possède 44 pv.
B.4 Type option
Définition 4
Le type 'a option Il s’agit d’un cas particulier de type somme qui représente soit une valeur particulière
None (”rien”), soit un élément de type 'a . Son principal objectif est de permettre à une fonction de ne ”rien”
renvoyer dans certains cas bien particuliers.
Le type ’a option est codé comme suit :
OCaml
1 type 'a option = Some of 'a | None ;;
Exemples :
1 (* fonction prédécesseur sur les entiers positifs. Pas défini en 0. *)
2 let prec x = if x = 0 then None else Some (x - 1) ;;
OCaml
3
4 let is_value y = match y with
5 | None -> false
6 | Some x -> true
7 ;;
14. En utilisant un type option, écrire une fonction tete qui prend en argument une liste et renvoie le premier
élément de cette liste s’il existe, et None sinon. (Ne pas utiliser la fonction [Link].)
Remarque : [Link] ne renvoie pas un type option, il génère une erreur si on l’appelle sur la liste vide.
√
15. (*) Écrire une fonction racine_carre de type int -> int option qui sur un entier 𝑥 renvoie 𝑥 si 𝑥 est un
carré (et None sinon). Indice : utilisez une affectation locale pour vous faciliter la tâche !
Aide : Pour tester si un flottant x est un entier, on peut utiliser la comparaison float_of_int (int_of_float x) = x
C Programmation impérative
Retour en terrain conquis avec la programmation impérative. Passons en revue les procédures auxquelles vous avez
l’habitude en C. ATTENTION. En OCaml, il est souvent plus efficace et plus élégant de programmer sans références et
sans effets de bord, même si tous les algorithmes ne s’y prêtent pas. Forcez-vous à vous en passer autant que possible.
Références :
Définition 5
La syntaxe pour définir une référence est let r = ref val .
Pour accéder au contenu d’une référence, on utilise !r (attention à ne pas oublier le ” !”).
On modifie le contenu d’une référence via la syntaxe r := new_val .
Exemples :
let x = ref 2;;
OCaml
1
2 x := !x + 1;;
3 print_int (!x);;
Remarque : La fonction incr en OCaml, de type int ref -> unit , permet d’incrémenter une référence.
incr r est l’équivalent de r := !r + 1 .
Séquence :
Définition 6
La séquence s’écrit avec un unique point virgule ; .
Exemple :
2. Oui, je sais, Dracaufeu est de type Feu et Vol, mais si ça vous dérange, libre à vous de coder de quoi représenter les doubles types !
3
TP VII. Introduction à OCaml (2)
let x = ref 2 in
OCaml
1
2 print_int (!x); incr x;
3 3 * (incr x; 2 + !x);; (*Ne faites pas ça pour de vrai, c'est illisible... *)
16. Prévoir le résultat de l’exemple précédent (valeur et type de l’expression). Que vaut le contenu de x à chaque
étape ?
Boucles :
La syntaxe des boucles est la suivante :
Définition 7
for var = val_init to val_finale do expr done
while cond do expr done
où expr est une expression de type unit (si ce n’est pas le cas, vous recevrez un Warning.)
Je vous rappelle que rajouter une indentation à vos codes est indispensable pour votre correcteur 3 , même si OCaml
ne l’exige pas.
Exemples :
1 for i = 0 to 10 do
2 print_int i;
3 print_newline ()
4 done
5 ;;
OCaml
6
7 let x = ref 0;;
8 while (!x < 10) do
9 x := (!x) + 1;
10 done
11 ;;
12 print_int (!x);;
Proposition 1
Attention, la boucle for s’exécute pour i prenant les valeurs val_init à val_finale incluses !
17. En utilisant une boucle for, définir une fonction puissance qui calcule la puissance sur les entiers.
1 # puissance 2 3 ;;
2 - : int = 8
18. En utilisant une boucle while, définir une fonction sdc qui effectue la somme des chiffres d’un entier. On utilisera
des divisions euclidiennes par 10.
1 # sdc 4948353 ;;
2 - : int = 36
D Pour occuper les plus rapides
19. Écrire une fonction miroir qui renvoie le symétrique d’un entier.
1 # miroir 16163223 ;;
2 - : int = 32236161
20. Coder l’exponentiation rapide (itérative) en OCaml (cf TD3).
3. Et donc pour vous !