Paradigmes de programmation — Introduction
Xavier Crégut
<Pré[email protected]>
ENSEEIHT Sciences du Numérique
Xavier Crégut (N7) Paradigmes de programmation — Introduction 1 / 12
Objectifs
Comprendre les principes de la programmation fonctionnelle L’illustrer au travers du langage Caml (ocaml)
1978 : ML (Meta Language) par Robin Milner Caml, Caml Light, Ocaml : la branche française Lancement de l’interpréteur : ocaml
Extension des fichiers .ml.
Xavier Crégut (N7) Paradigmes de programmation — Introduction 2 / 12
Principe de la programmation fonctionnelle
Pas d’effet de bord
Pas d’état (et donc pas de changement d’état)
Tous les sous-programmes sont des fonctions qui ne modifient pas leurs paramètres (ni aucune autre donnée) et calculent de nouvelles valeurs (objets)
Tout est expression (avec une valeur) !
Décomposition fonctionnelle Programme(x1...xM) =
F (e1, e2, ..., eN) Avec
e1 = F1(..., xI, ...) e2 = F2(..., xI, ...) ...
eN = FN(..., xI, ...)
Intérêt du fonctionnel :
pas d’ordre sur d’évaluation des expressions en paramètre parallèlisation naturelle (exécution en // des expressions) lisibilité (et donc maintenance) améliorée (pas d’état) tests en boîte noire facilités (entrées et résultats explicites)
Structures de contrôle
1 Conditionnelle :Si condition Alors valeurVraie Sinon valeurFaux FinSi
2 Composition fonctionnelle (voir ci-dessus)
3 Récursivité (le pendant des boucles).
Xavier Crégut (N7) Paradigmes de programmation — Introduction 3 / 12
Exemple : distance entre deux points en Caml
1 (** Distance entre deux points. Chaque point est réprenté
2 * par son abscisse et son ordonnée.
3 **)
4 let distance p1 p2 = (* distance prend deux paramètres p1 et p2 *)
5 let carre x=x *. x (* définition de la fonction carre *)
6 and(x1, y1) = p1 (* les coordonnées du point p1 *)
7 and(x2, y2) = p2 (* et du point p2 *)
8 in
9 letdx2 =carre (x1 -. x2) (* le carré de la distance sur les X *)
10 and dy2 =carre (y1 -. y2) (* et sur les Y *)
11 in
12 sqrt (dx2 +. dy2) (* la distance entre p1 et p2 *)
13 ;;
14 (* val distance : float * float -> float * float -> float = <fun> *)
15
16 let main=
17 print_string("distance (0, 0) (3, 4) = ") ;
18 print_float(distance (0.0, 0.0) (3.0, 4.0)) ;;
19 20 main;
Xavier Crégut (N7) Paradigmes de programmation — Introduction 4 / 12
Quelques explications
letpermet d’associer un objet à un nom.
let g= 5 ;; (* définition d'un nom global *)
let a= 1 andb = 2;; (* définition de plusieurs noms, indépendants *) let l= 2 in l*g;; (* l est un nom local à l'expression après in *) let somme x y= x+. y;; (* définition d'une fonction *) (* signature : somme : float -> float -> float) *) Inférence de type :le programmeur n’est pas obligé de donner les types. Ils sont inférés.
Ocaml est un langage àtypage statique fort(pas de conversion implicite).
5est un entier (int) et5.(ou5.0) est un réel (float) + - * /: opérteurs sur les entiers (int)
+. -. *. /.: opérteurs sur les réels (float)
Appel d’une fonction :on fournit les paramètres effectifs (sous l’interpréteur ocaml)
# somme 3. 4.5;;
- : float = 7.5
# somme 3 4.5;;
Error: 3has typeint but an expression was expected of typefloat Laséquenceest marquée par;. Attention, ce n’est pas fonctionnel ! Les fonctionsprint_*ont un effet de bord... sur le terminal !
Xavier Crégut (N7) Paradigmes de programmation — Introduction 5 / 12
Conditionnelles : Si et Filtrage
LeSiest un si fonctionnel qui doit avoir une valeur pour vraietune valeur pour faux.
1 let rec fact n=
2 if n<= 1
3 then1
4 elsen* fact(n- 1) ;;
5 (* val fact : int -> int = <fun> *)
On doit utiliserlet recpour définir une fonction récursive.
Lefiltrage(match) permet de filtrer sur la structure d’un objet.
Le motif du filtrage (avant->) ne peut contenir que des constantes ou des noms libres (non associés à une valeur)
1 let rec fact n=
2 if n< 0
3 thenfailwith ("n négatif : n = "^ (string_of_int n))
4 else
5 match n with
6 | 0 -> 1
7 | 1 -> 1
8 | p-> p* fact(p- 1) ;;
9
10 print_string("fact(3) = " ^ (string_of_int(fact3)) ^ "\n");;
11 print_string("fact(0) = " ^ (string_of_int(fact0)) ^ "\n");;
12 fact(-2);; (* Exception: Failure "n négatif : n = -2" *)
Xavier Crégut (N7) Paradigmes de programmation — Introduction 6 / 12
Le filtrage sur des n-uplets : match
1 let sur_axe pt=
2 match pt with
3 | (0.0, _) ->true
4 | (_, 0.0) ->true
5 | _ -> false
6 ;;
7
8 sur_axe (0.0, 1.0);; (* true *)
9 sur_axe (1.0, 0.0);; (* true *)
10 sur_axe (2.0, 3.0);; (* false *)
Le filtrage permet de filtrer sur la structure des objets.
C’est son principal intérêt ! À suivre avec les listes et les constructeurs de type.
Xavier Crégut (N7) Paradigmes de programmation — Introduction 7 / 12
Constructeurs de type
Principe :regrouper plusieurs informations (potentiellement de types différents) sous un même type.
Exemple :Une monnaie caractérisée par une valeur (float) et une devise (string).
1 type devise= Euro|Dollar;; (* Euro et Dollar : constructeurs constants *)
2 type monnaie=Monnaie of float *devise ;;
3
4 let m1 =Monnaie (5.,Euro) ;;
5 let m2 =Monnaie (7.,Euro) ;;
À droite du = on a desconstructeurs de typedont le nom commence par une majuscule.
Autre définition possible du type monnaie :
1 type monnaie=Euro of float |Dollar of float ;;
2
3 let m1 =Euro (5.) ;;
4 let m1 =Euro (7.) ;;
5
6 let vers_euro monnaie change =
7 match monnaiewith
8 | Euro(v) -> monnaie
9 | Dollar(v) ->Euro(v*. change) ;;
Xavier Crégut (N7) Paradigmes de programmation — Introduction 8 / 12
Les listes
ocaml définit un type liste (list) avec les opérations :
construire une liste à partir de ses éléments :letl1 = [ 1; 3; 4; 2] ;;
Attention au « ; » qui sépare les éléments []est la liste vide.
construire une liste à partir d’un élément et d’une liste « : : » let l2 = 10 ::l1 ;; (* l2 = [10; 1; 3; 4; 2] *)
hd(head) pour récupérer le premier élément let premier=List.hd l1 ;; (* premier = 1 *) tl(tail) : la liste sans le premier élément
let autres= List.tl l1 ;; (* autres = [3; 4; 2] *)
Xavier Crégut (N7) Paradigmes de programmation — Introduction 9 / 12
Exemple : utilisation d’une liste
1 open List;; (* pour éviter d'écrire List.hd et List.tl *)
2
3 let rec somme0 liste=
4 if liste =[]
5 then0
6 else(hd liste) + (somme0 (tl liste)) ;;
7
8 let rec taille0 liste=
9 if liste =[]
10 then0
11 else1 + (taille0 (tl liste)) ;;
12
13 let rec somme liste =
14 match liste with
15 | [] -> 0
16 | tete:: suite -> tete + (somme suite) ;;
17
18 let rec taille liste=
19 match liste with
20 | [] -> 0
21 | _ ::suite -> 1 + (taille suite) ;;
Xavier Crégut (N7) Paradigmes de programmation — Introduction 10 / 12
Fonction et application partielle
Exempled’une fonctionegauxqui teste l’égalité un entier (premier paramètre) et un réel deuxième paramètre et retourne donc un booléen.
# letegaux a b =float(a) = b;;
val egaux :int -> float -> boolean= <fun>
Attention :=égalité logique et==(égalité physique)
La signature de la fonction peut aussi être lue comme : int -> (float -> boolean)
En d’autre terme, une fonction qui prend en paramètre un entier et retourne une fonction qui prend en paramètre un réel et retourne un booléen.
Application partielle :appel d’une fonction en ne donnant que les premiers paramètres
# letest_nul =egaux 0;;
val est_nul: float -> bool= <fun>
# est_nul2.0;;
- : bool= false
# est_nul0.0;;
- : bool= true
Xavier Crégut (N7) Paradigmes de programmation — Introduction 11 / 12
Ordre supérieur : des fonctions en paramètre
Une fonction est un objet comme les autres.
Il peut être passé en paramètre et appliqué.
1 let compose f g x= f(g x) ;;
2 (* val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun> *)
3 (* 'a, 'b et 'c indiquent que la fonction est générique *)
4
5 let carre a= a*a ;;
6 let oppose a = - a;;
7 compose oppose carre 2 ;; (* -4 *) Exemple :Opérateurmapsur les listes
let l= [1; 2; 3; 4] and carre x= x*x in List.map carre l;;
Xavier Crégut (N7) Paradigmes de programmation — Introduction 12 / 12