Cours no 2 : Itération. Du impératif au style fonctionnel 1

Transcription

Cours no 2 : Itération. Du impératif au style fonctionnel 1
Univ. Lille1 - Licence info 3ème année
2012-2013
Expression Logique et Fonctionnelle . . . Évidemment
o
Cours n 2 : Itération. Du impératif au style fonctionnel
1
Itérateurs sur les listes
1.1
map
La fonction
List.map
est un itérateur sur les listes. Elle est du type
(0 a → 0 b) → 0 a list → 0 b list
et, appliquée à une fonction f et une liste [a1 ; a2 ; . . . ; an ] renvoie la liste [f (a1 ); f (a2 ); . . . ; f (an )].
En voici deux exemples d'utilisation.
#
#
-
List.map (fun x -> 2*x) [0; 1; 2; 3; 4] ;;
: int list = [0; 2; 4; 6; 8]
List.map char_of_int [69; 76; 70; 69] ;;
: char list = [’E’; ’L’; ’F’; ’E’]
En voici une réalisation récursive (non terminale) en Caml à l'aide d'un ltrage de motif.
let rec map = fun f l ->
match l with
| x::l’ -> (f x)::(map f l’)
| _ -> []
1.2
fold_left
let rec fold_left = fun f x l ->
match l with
| y::l’ -> fold_left f (f x y) l’
| _ -> x
2
2.1
Passer de l'impératif au fonctionnel
État
Un programme impératif agit sur son état en modiant la valeur des variables qui le constituent.
Un état peut être représenté en programmation fonctionnelle par un n-uplet des valeurs des variables.
Une instruction qui transforme un état (comme par exemple une aectation) peut alors être considérée
comme une fonction qui à un n-uplet des valeurs des variables, associe un nouvel n-uplet.
2.2
Séquence
Voici une fonction écrite en C qui calcule la puissance 15ème de l'entier qu'on lui passe en paramètre.
L'algorithme suivi permet ce calcul en eectuant cinq multiplications uniquement (ce qui correspond
au nombre minimal de multiplications permettant un tel calcul). Le calcul est réalisé en utilisant trois
variables locales b, c et d.
int puissance15(int a) {
int b,c,d ;
// b = ??, c = ??, d = ??
b = a *a*a ;
// b = a^3, c = ??, d = ??
c = b *b ;
// b = a^3, c = a^6, d = ??
d = c *c ;
// b = a^3, c = a^6, d = a^12
1
return
b*d ;
}
L'état de l'environnement dans lequel s'eectue le calcul est décrit par les valeurs des trois variables
locales. C'est donc ici un triplet d'entiers.
Conformément à ce qui a été dit ci-dessus, chacune des trois aectations successives peut être vue
comme une fonction transformant l'état en un autre.
La première aectation change la valeur de la variable b et laisse les deux autres variables inchangées.
let f1 = fun (b,c,d) -> (a*a*a,c,d)
La deuxième aectation change la valeur de la variable c.
let f2 = fun (b,c,d) -> (b,b*b,d)
Et la troisième aectation change la valeur de d.
let f3 = fun (b,c,d) -> (b,c,c*c)
L'état initial des trois variables n'est pas déterminé par leur déclaration. Leur valeur peut donc être
quelconque. On la pose ici arbitrairement égale à 0. La séquence de calcul peut donc être vue comme
l'enchaînement suivant :
f1
f2
f3
(0, 0, 0) −→ (a3 , 0, 0) −→ (a3 , a6 , 0) −→ (a3 , a6 , a12 ).
Une traduction de la fonction C ci-dessus est obtenue en traduisant la séquence des trois aectations
par une composition des trois fonctions.
let puissance15 = fun a ->
let f1 = fun (b,c,d) -> (a * a * a, c, d)
and f2 = fun (b,c,d) -> (b, b * b, d)
and f3 = fun (b,c,d) -> (b, c, c * c) in
let b,c,d = f3 (f2 (f1 (0, 0, 0))) in
b * d
La traduction en style fonctionnel de la fonction puissance15 donnée ci-dessus suit un schéma très
général de représentation des variables utilisées par la version impérative par un triplet d'entiers, les
transformations successives étant elles représentées par composition de trois fonctions. Mais on pourrait
en donner une autre version purement fonctionnelle et moins lourde comme par exemple
let puissance15
let b = a * a
let c = b * b
let d = c * c
b * d
= fun a ->
*a in
in
in
2.3
Conditionnelle
2.4
Itération non conditionnelle
int expo(int a, int n) {
int i,p ;
p = 1 ;
for (i=1;i<=n;i++) {
p = p *a ;
}
return
p ;
}
2
(**
itere : (’a -> ’a) -> int -> ’a -> ’a
[itere f n e] = f (f ...(f e) ...)
{b CU :} [n >= 0]
*)
let rec itere = fun f n e ->
if n = 0 then
e
else
itere f (n - 1) (f e)
let expo = fun a n ->
let _,_,p = itere (fun (a,i,p) -> (a,i+1,a*p)) n (a,1,1) in
p
2.5
Itération conditionnelle
int expo_rapide(int a, int n) {
int r,s,k ;
r = 1 ;
s = a ;
k = n ;
while (k != 0) {
if (k%2 == 1) r = r*s ;
s = s *s ;
k = k / 2 ;
}
return
r ;
}
(**
tantque : (’a -> ’a) -> (’a -> bool) -> ’a -> ’a
*)
let rec tantque = fun f p e ->
if p e then
tantque f p (f e)
else
e
let expo_rapide = fun a n ->
let r,_,_ = tantque
(fun (r,s,k) -> if k mod 2 <> 0 then
(r*s, s*s, k/2)
else
(r, s*s, k/2))
(fun (r,s,k) -> k <> 0)
(1,a,n) in
r
3