9 Ordre sup´erieur
# let carre_couple (x,y) = (x*x, y*y);;
val carre_couple : int * int -> int * int = <fun>
# let double_couple (x,y) = (2*x, 2*y);;
val double_couple : int * int -> int * int = <fun>
# let app_couple f (x,y) = (f x, f y);;
val app_couple : (’a -> ’b) -> ’a * ’a -> ’b * ’b = <fun>
Let fonctions carre_couple et double_couple ont la mˆeme structure : appliquer une fonction aux
membres d’un couple. Grˆace `a l’ordre sup´erieur, on peut d´efinir une fonction plus g´en´erique qui attend
la fonction `a appliquer.
Noter dans le type de app_couple :
– les ’a et ’b. On ne sait pas ici quel sera le type des ´el´ements du couple. La fonction marche quelque
soit le type ’a et le type ’b. Mais il faut bien que les deux ´el´ements du couple aient le mˆeme type
puisqu’ils sont tous les deux arguments de f.
On parle de polymorphisme.’a et ’b sont appel´ees des variables de type. On les lit parfois α, β en
r´ef´erence au λ-calcul.
– les parenth`eses. ’a -> ’b -> ’a * ’a -> ’b * ’b serait une fonction `a 3 arguments, respective-
ment de type ’a,’b et ’a * ’a. Autrement dit, l’application (et la fl`eche) n’est pas associative `a
gauche.
# let carre_double = app_couple (function x -> x*x);;
val carre_double : int * int -> int * int = <fun>
# let doublef_couple = app_couple (function x -> 2. *. x);;
val doublef_couple : float * float -> float * float = <fun>
# let convert_couple = app_couple (float_of_int);;
val convert_couple : int * int -> float * float = <fun>
L’application partielle permet de d´efinir beaucoup de fonctions agissant sur les couples.
# let compose f g = function x -> f( g(x) );;
val compose : (’a -> ’b) -> (’c -> ’a) -> ’c -> ’b = <fun>
Le grand classique de l’ordre sup´erieur. . .
10 Reconnaissance de motif (“Pattern matching”)
# let rec fac =
function
|0->1
| n -> fac (n-1) * n;;
val fac : int -> int = <fun>
# let rec fact n = if n=0 then 1 else n*(fact (n-1));;
val fact : int -> int = <fun>
La construction function peut aussi introduire une reconnaissance de motif. Il s’agit d’une g´en´eralisation
du switch case. En particulier, les valeurs reconnues ne sont pas forc´ement constantes et peuvent d´efinir
des nouvelles variables (ici, n).
# let rec fibo =
function
|0->1
|1->1
| n -> (fibo (n-1)) + (fibo (n-2));;
val fibo : int -> int = <fun>
5