Appel initial : Le premier appel de la fonction.
Appel initial : Le premier appel de la fonction.
Appel initial : Le premier appel de la fonction.
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
Licence 1 Année 2011 - 2012<br />
UE Informatique<br />
Programmation <strong>fonction</strong>nelle<br />
Thierry RAEDERSDORFF<br />
TD n°6<br />
On distingue <strong>de</strong>ux manières d'<strong>appel</strong>er une <strong>fonction</strong> récursive :<br />
• <strong>Appel</strong> <strong>initial</strong> : <strong>Le</strong> <strong>premier</strong> <strong>appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong>.<br />
• <strong>Appel</strong> récursif : <strong>Appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong> lors <strong>de</strong> l'exécution <strong>de</strong> <strong>la</strong> <strong>fonction</strong> récursive.<br />
Récursivité c<strong>la</strong>ssique :<br />
• Gestion <strong>de</strong>s exceptions<br />
On gère ici les cas où les arguments <strong>de</strong> <strong>la</strong> <strong>fonction</strong> ne permettent pas <strong>de</strong><br />
fournir un résultat.<br />
• Gestion <strong>de</strong>s cas particuliers<br />
On gère ici les cas où les arguments <strong>de</strong> <strong>la</strong> <strong>fonction</strong> permettent <strong>de</strong> fournir un<br />
résultat mais qui ne rentre pas dans le cadre <strong>de</strong> l'algorithme général. .<br />
• Cas simple :<br />
Dans le cas simple <strong>la</strong> <strong>fonction</strong> ne s'<strong>appel</strong>le pas elle-même.<br />
On défnit un critère d'arrêt <strong>de</strong> <strong>la</strong> <strong>fonction</strong> ainsi que le résultat simple<br />
correspondant à ce cas. Ce résultat correspond à l'<strong>initial</strong>isation du calcul.<br />
• Cas général :<br />
Dans le cas général un calcul intermédiaire est réalisé.<br />
Un calcul intermédiaire utilisera le résultat d'un <strong>appel</strong> récursif <strong>de</strong> <strong>la</strong><br />
<strong>fonction</strong>. L'<strong>appel</strong> récursif empile les <strong>appel</strong>s <strong>de</strong> <strong>la</strong> <strong>fonction</strong>. Ce n'est qu'au<br />
retour <strong>de</strong> l'<strong>appel</strong> récursif que le calcul intermédiaire sera réalisé, dans <strong>la</strong><br />
phase où on désempile les <strong>appel</strong>s.<br />
Cas A :<br />
On pourra faire le choix d'écrire une seule <strong>fonction</strong> récursive qui gère les quatre<br />
situations. L'inconvénient étant qu'à chaque <strong>appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong> on se <strong>de</strong>man<strong>de</strong>ra si<br />
nous sommes en présence d'une exception ou d'un cas particulier.<br />
Cas B :<br />
On pourra faire le choix d'écrire une <strong>fonction</strong> principale non récursive qui gère les<br />
exceptions et les cas particuliers et qui assure, si on n'est pas dans l'un <strong>de</strong>s <strong>de</strong>ux cas<br />
précé<strong>de</strong>nts, le <strong>premier</strong> <strong>appel</strong> d'une <strong>fonction</strong> récursive auxiliaire qui applique<br />
l'algorithme général.
Exemple :<br />
Ecrire une <strong>fonction</strong> f qui calcule n!/p! avec n>=0 et p>=0<br />
On désire simplifer le calcul. On calculera dans le cas général n(n-1)(n-2)...(p+1)<br />
Cas A :<br />
Si n ou p sont négatifs nous sommes en présence d'une exception.<br />
Si on a n
Récursivité terminale :<br />
Une <strong>fonction</strong> est récursive terminale quand le calcul d'un résultat intermédiaire est réalisé avant<br />
l'<strong>appel</strong> récursif <strong>de</strong> <strong>la</strong> <strong>fonction</strong>. On utilisera un accumu<strong>la</strong>teur pour empiler les résultats<br />
intermédiaires. Au <strong>premier</strong> <strong>appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong> on fournira <strong>la</strong> valeur <strong>initial</strong>e <strong>de</strong> l' accumu<strong>la</strong>teur.<br />
On utilise <strong>de</strong>ux <strong>fonction</strong>s<br />
Une <strong>fonction</strong> principale non récursive qui gère<br />
• La gestion <strong>de</strong>s exceptions<br />
S'il existe <strong>de</strong>s exceptions, <strong>la</strong> <strong>fonction</strong> vérife si les arguments fournis lors <strong>de</strong><br />
l'<strong>appel</strong> appartiennent au domaine <strong>de</strong> validité. Si une exception est<br />
rencontrée <strong>la</strong> <strong>fonction</strong> ne réalise pas le calcul. On utilise les <strong>fonction</strong>s<br />
prédéfnies failwith ou assert pour interrompre l'exécution <strong>de</strong> <strong>la</strong> <strong>fonction</strong>.<br />
• La gestion <strong>de</strong>s cas particuliers<br />
S'il existe <strong>de</strong>s cas particuliers, ils sont gérés dans <strong>la</strong> <strong>fonction</strong> principale. Il<br />
s'agit <strong>de</strong> cas qui retourne un résultat prévu mais qui n'utilise pas<br />
l'algorithme général.<br />
• <strong>Le</strong> <strong>premier</strong> <strong>appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong> auxiliaire récursive.<br />
Lors <strong>de</strong> cet <strong>appel</strong> on fournira <strong>la</strong> valeur <strong>initial</strong>e <strong>de</strong> l'accumu<strong>la</strong>teur suivi <strong>de</strong>s<br />
arguments <strong>de</strong> <strong>la</strong> <strong>fonction</strong> <strong>initial</strong>e. L'accumu<strong>la</strong>teur est utilisé pour réaliser<br />
les calculs intermédiaires.<br />
Une <strong>fonction</strong> auxiliaire récursive qui gère<br />
• le cas simple :<br />
Dans le cas simple <strong>la</strong> <strong>fonction</strong> ne s'<strong>appel</strong>le pas elle-même.<br />
On défnit un critère d'arrêt <strong>de</strong> <strong>la</strong> <strong>fonction</strong> ainsi que le résultat <strong>de</strong> <strong>la</strong><br />
<strong>fonction</strong>. Ce résultat correspond au résultat fnal <strong>de</strong> <strong>la</strong> <strong>fonction</strong>, il est<br />
présent dans l'accumu<strong>la</strong>teur.<br />
• le cas général :<br />
Dans le cas général un calcul intermédiaire est réalisé avant l'<strong>appel</strong> récursif<br />
<strong>de</strong> <strong>la</strong> <strong>fonction</strong>, ce calcul modife <strong>la</strong> valeur <strong>de</strong> l'accumu<strong>la</strong>teur. L'<strong>appel</strong> récursif<br />
empile les <strong>appel</strong>s <strong>de</strong> <strong>la</strong> <strong>fonction</strong>.<br />
let f n p =<br />
let rec calcul accumu<strong>la</strong>teur n p =<br />
if n=p then accumu<strong>la</strong>teur<br />
else calcul (n*accumu<strong>la</strong>teur) (n-1) p<br />
in<br />
if n
Exemple factorielle <strong>de</strong> n :<br />
Récursivité c<strong>la</strong>ssique :<br />
let rec f n = if n
R<strong>appel</strong> : On dispose en ocaml<br />
• d'un module Random qui contient <strong>de</strong>s <strong>fonction</strong>s qui permettent <strong>de</strong> réaliser <strong>de</strong>s<br />
tirages aléatoires. La <strong>fonction</strong> Random.int <strong>appel</strong>ée avec un argument x<br />
retourne un entier compris entre 0 et x-1.<br />
Random.int max → entier entre 0 et max-1<br />
Random.int (max+1) → entier entre 0 et max<br />
Random.int max + 1 → entier entre 1 et max<br />
• D'une <strong>fonction</strong> prédéfinie read_int qui permet <strong>de</strong> lire un entier saisi au<br />
c<strong>la</strong>vier.<br />
• D'une <strong>fonction</strong> prédéfinie List .map qui permet d'appliquer une <strong>fonction</strong> f à<br />
l'ensemble <strong>de</strong>s éléments d'une liste afin <strong>de</strong> générer une nouvelle liste<br />
[a1;a2;...;an] -> [f a1;f a2;..;f an]<br />
let rec map f liste =<br />
match liste with<br />
|[] -> []<br />
|h::t -> f h::map f t;;
Exercices complémentaires :<br />
a. Création d'une liste d'entiers qui contient les n <strong>premier</strong>s entiers > 0<br />
Récursivité c<strong>la</strong>ssique :<br />
let rec create_first_n_strictly_positive_integers_list n =<br />
match n=0 with<br />
|true -> []<br />
|_ -> n::create_first_n_strictly_positive_integers_list (n-1);;<br />
val create_first_n_strictly_positive_integers : int -> int list = <br />
create_first_n_strictly_positive_integers_list 6;;<br />
- : int list = [6; 5; 4; 3; 2; 1]<br />
<strong>Le</strong>s entiers sont ordonnées par ordre décroissant. Si on désire les ordonner par ordre<br />
croissant on utilisera l'opérateur <strong>de</strong> concaténation au lieu <strong>de</strong> l'opérateur d'insertion pour<br />
construire <strong>la</strong> liste.<br />
let rec create_first_n_strictly_positive_integers_list n =<br />
match n=0 with<br />
|true -> []<br />
|_ -> create_first_n_strictly_positive_integers_list (n-1)@[n];;<br />
val create_first_n_strictly_positive_integers : int -> int list = <br />
create_first_n_strictly_positive_integers_list 6;;<br />
- : int list = [1; 2; 3; 4; 5; 6]<br />
Récursivité terminale :<br />
let create_first_n_strictly_positive_integers_list n =<br />
let rec auxiliaire accumu<strong>la</strong>teur n =<br />
match n=0 with<br />
|true -> accumu<strong>la</strong>teur<br />
|_ -> auxiliaire (n::accumu<strong>la</strong>teur) (n-1)<br />
in<br />
auxiliaire [] n;;<br />
val create_first_n_strictly_positive_integers_list : int -> int list = <br />
create_first_n_strictly_positive_integers_list 6;;<br />
- : int list = [1; 2; 3; 4; 5; 6]
. Création d'une liste <strong>de</strong> n entiers tirés aléatoirement entre a et b.<br />
Nombre <strong>de</strong> valeurs possible : b-a+1<br />
Tirage aléatoire : Random.int (b-a+1)<br />
Résultat compris entre : 0 et b-a<br />
Plus petite valeur possible : a<br />
Plus gran<strong>de</strong> valeur possible : b<br />
Tirage aléatoire d'un entier compris entre a et b : Random.int (b-a+1) + a<br />
Récursivité c<strong>la</strong>ssique :<br />
let rec create_randomly_integers_list n a b =<br />
match n=0 with<br />
|true -> []<br />
|_ -> let x = (Random.int (b-a+1) + a) in<br />
x::create_randomly_integers_list (n-1) a b;;<br />
val create_randomly_integers_list : int -> int -> int -> int list = <br />
Récursivité terminale :<br />
let create_randomly_integers_list n a b =<br />
let rec auxiliaire accumu<strong>la</strong>teur n =<br />
match n=0 with<br />
|true -> accumu<strong>la</strong>teur<br />
|_ -> let x = (Random.int (b-a+1) + a) in<br />
auxiliaire (x::accumu<strong>la</strong>teur) (n-1)<br />
in<br />
auxiliaire [] n;;<br />
val create_first_n_strictly_positive_integers_list : int -> int list =
Exercice 1<br />
1°/ Ecrire une <strong>fonction</strong> récursive qui permet <strong>de</strong> rentrer au c<strong>la</strong>vier, les éléments d'une liste<br />
d'entiers positifs ou nuls, <strong>la</strong> saisie s'arrête quand <strong>la</strong> valeur entrée est négative.<br />
a. Création d'une nouvelle liste<br />
Récursivité c<strong>la</strong>ssique :<br />
let rec lire_int_list () =<br />
let x = read_int() in<br />
if x int list = <br />
L'absence d'argument d'une <strong>fonction</strong> doit être représenté par les parenthèses () dans l'en-ête <strong>de</strong> <strong>la</strong><br />
<strong>fonction</strong> et lors <strong>de</strong> l'<strong>appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong>.<br />
lire_int_list;;<br />
- : unit -> int list = <br />
lire_int_list ();;<br />
1<br />
2<br />
3<br />
-1<br />
- : int list = [1; 2; 3]<br />
Récursivité terminale :<br />
let lire_int_list () =<br />
let rec aux accumu<strong>la</strong>teur =<br />
let x = read_int() in<br />
if x
lire_int_list ();;<br />
1<br />
2<br />
3<br />
-1<br />
- : int list = [3; 2; 1]<br />
La liste est inversée.<br />
let lire_int_list () =<br />
let rec aux accumu<strong>la</strong>teur =<br />
let x = read_int() in<br />
if x int list = <br />
lire_int_list ();;<br />
1<br />
2<br />
3<br />
-1<br />
- : int list = [1; 2; 3]
. Complétez une liste<br />
Récursivité c<strong>la</strong>ssique :<br />
let rec complete liste =<br />
let x = read_int() in<br />
if x int list = <br />
complete [5;8];;<br />
1<br />
2<br />
-1<br />
- : int list = [1; 2; 5; 8]<br />
Récursivité terminale :<br />
let complete liste =<br />
let rec aux accumu<strong>la</strong>teur liste =<br />
let x = read_int() in<br />
if x int list = <br />
complete [5;8];;<br />
1<br />
2<br />
-1<br />
- : int list = [2; 1; 5; 8]<br />
let complete liste =<br />
let rec aux accumu<strong>la</strong>teur liste =<br />
let x = read_int() in<br />
if x int list = <br />
complete [5;8];;<br />
1<br />
2<br />
-1<br />
- : int list = [1; 2; 5; 8]
2°/ Ecrire une <strong>fonction</strong> qui permet d’afficher les valeurs contenues dans une liste d'entier à<br />
raison d'une valeur par ligne.<br />
Récursivité c<strong>la</strong>ssique ou terminale ?<br />
let rec affiche_int_list liste =<br />
match liste with<br />
|[] -> ()<br />
|h::t -> begin<br />
end;;<br />
val affiche_int_list : int list -> unit = <br />
affiche_int_list [1;2;3];;<br />
1<br />
2<br />
3<br />
- : unit = ()<br />
print_int h;<br />
print_newline ();<br />
affiche_int_list t<br />
let rec affiche_int_list liste =<br />
match liste with<br />
|[] -> ()<br />
|h::t -> print_int h;print_newline ();affiche_int_list t;;<br />
Récursivité c<strong>la</strong>ssique<br />
let rec affiche_int_list liste =<br />
match liste with<br />
|[] -> []<br />
|h::t -> print_newline ()::print_int h::affiche_int_list t;;<br />
val affiche_int_list : int list -> unit list = <br />
affiche_int_list [1;2;3];;<br />
3<br />
2<br />
1<br />
- : unit list = [(); (); (); (); (); ()]
Récursivité terminale<br />
let affiche_int_list liste =<br />
let rec aux accumu<strong>la</strong>teur liste =<br />
match liste with<br />
|[] -> accumu<strong>la</strong>teur<br />
|h::t -> aux (print_newline ()::print_int h::accumu<strong>la</strong>teur) t<br />
in<br />
aux [] liste;;<br />
affiche_int_list [1;2;3];;<br />
1<br />
2<br />
3<br />
- : unit list = [(); (); (); (); (); ()]
3°/ Ecrire une <strong>fonction</strong> qui affiche sur une ligne <strong>de</strong> l'écran, un nombre <strong>de</strong> X égal à <strong>la</strong> valeur <strong>de</strong><br />
l'élément <strong>de</strong> <strong>la</strong> liste, et ce<strong>la</strong> pour tous les termes <strong>de</strong> <strong>la</strong> liste en respectant l'ordre.<br />
3°.a/ Fonction ligne qui affiche n fois le caractère c sur une ligne puis passe à <strong>la</strong> ligne.<br />
Récursivité c<strong>la</strong>ssique<br />
let ligne c n =<br />
let rec affiche c n =<br />
if n=0 then []<br />
else print_char c::affiche c (n-1)<br />
in<br />
print_newline ()::affiche c n;;<br />
val affiche_char : char -> int -> unit list = <br />
ligne 'X' 5;;<br />
XXXXX<br />
- : unit list = [(); (); (); (); (); ()]<br />
La <strong>fonction</strong> principale affiche_char, n'est pas récursive, elle <strong>initial</strong>ise le <strong>premier</strong> <strong>appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong><br />
récursive affiche. Après exécution <strong>de</strong> <strong>la</strong> <strong>fonction</strong> affiche on exécute <strong>la</strong> <strong>fonction</strong> print_newline () qui<br />
assure le passage à <strong>la</strong> ligne.<br />
Récursivité terminale traditionnelle<br />
let ligne c n =<br />
let rec affiche acc c n =<br />
if n=0 then print_newline ()<br />
else affiche (print_char c) c (n-1)<br />
in<br />
affiche () c n;;<br />
val ligne : char -> int -> unit = <br />
ligne 'X' 5;;<br />
XXXXX<br />
- : unit = ()<br />
Récursivité terminale s'appliquant à un affichage donc à un résultat <strong>de</strong> type unit → cas où on peut se<br />
passer <strong>de</strong> l'accumu<strong>la</strong>teur.<br />
let rec ligne c n =<br />
if n=0 then print_newline ()<br />
else print_char c;ligne c (n-1);;<br />
ou encore<br />
let rec ligne c n =<br />
if n=0 then print_newline ()<br />
else begin<br />
print_char c;<br />
ligne c (n-1)<br />
end;;<br />
val ligne : char -> int -> unit =
Exemple complémentaire:<br />
Fonction affiche_int qui affiche les n <strong>premier</strong>s entiers > 0 sur une ligne puis passe à <strong>la</strong> ligne.<br />
Récursivité c<strong>la</strong>ssique<br />
let affiche_int n =<br />
let rec affiche n =<br />
if n=0 then []<br />
else print_int n::affiche (n-1)<br />
in<br />
print_newline ()::affiche n;;<br />
val affiche_int : int -> unit list = <br />
affiche_int 4;;<br />
1234<br />
- : unit = ()<br />
Remarquez l'ordre dans lequel les entiers sont affichés. <strong>Le</strong> <strong>premier</strong> affichage est réalisé quand on a<br />
rencontré le cas simple. <strong>Le</strong> <strong>premier</strong> entier affiché sera donc 1.<br />
Récursivité terminale<br />
let affiche_int n =<br />
let rec affiche acc u n =<br />
if acc>n then print_newline ()<br />
else affiche (acc+1) (print_int acc) n<br />
in<br />
affiche 1 () n;;<br />
val affiche_int : int -> unit list = <br />
affiche_int 4;;<br />
1234<br />
- : unit = ()<br />
L'accumu<strong>la</strong>teur n'est pas utilisé. On peut aussi écrire :<br />
let rec affiche_int n =<br />
if n=0 then print_newline ()<br />
else<br />
begin<br />
print_int n;affiche_int (n-1)<br />
end;;<br />
affiche_int 4;;<br />
4321<br />
- : unit = ()
let rec affiche_int n =<br />
if n=0 then print_newline ()<br />
else<br />
begin<br />
affiche_int (n-1);print_int n<br />
end;;<br />
affiche_int 4;;<br />
1234- : unit = ()<br />
let affiche_int n =<br />
let rec affiche n =<br />
if n=0 then ()<br />
else<br />
begin<br />
affiche (n-1);print_int n<br />
end<br />
in<br />
affiche n;print_newline ();;<br />
val affiche_int : int -> unit -> unit = <br />
affiche_int 4;;<br />
1234<br />
- : unit = ()
3°.b/ Fonction histogramme qui affiche un histogramme horizontal représentant les entiers<br />
contenus dans une liste.<br />
Unit list :<br />
Récursivité c<strong>la</strong>ssique<br />
let rec histogramme liste =<br />
match liste with<br />
|[] -> []<br />
|h::t -> ligne 'X' h::histogramme t;;<br />
val histogramme : int list -> unit list list = <br />
histogramme [1;2;3];;<br />
XXX<br />
XX<br />
X<br />
- : unit list = [(); (); ()]<br />
Récursivité terminale<br />
let histogramme liste =<br />
let rec aux accumu<strong>la</strong>teur liste =<br />
match liste with<br />
|[] -> accumu<strong>la</strong>teur<br />
|h::t -> aux (ligne 'X' h::accumu<strong>la</strong>teur) t<br />
in<br />
aux [] liste;;<br />
val histogramme : int list -> unit list list = <br />
histogramme [1;2;3];;<br />
X<br />
XX<br />
XXX<br />
- : unit list = [(); (); ()]<br />
Unit<br />
let rec histogramme liste =<br />
match liste with<br />
|[] -> ()<br />
|h::t -> begin ligne 'X' h; histogramme t end;;
4°/ Ecrire une <strong>fonction</strong> qui permet d'augmenter <strong>de</strong> <strong>la</strong> valeur constante 3, tous les éléments <strong>de</strong><br />
<strong>la</strong> liste.<br />
let rec augmente liste x =<br />
match liste with<br />
|[] -> []<br />
|h::t -> (+) h x::(augmente t x);;<br />
val augmente : int list -> int -> int list = <br />
augmente [1;8;7] 3;;
5°/ Ecrire une <strong>fonction</strong> qui, à partir d'une liste, permet <strong>de</strong> créer une nouvelle liste comportant<br />
le même nombre d'éléments, dont le <strong>premier</strong> élément est égal à <strong>la</strong> moyenne <strong>de</strong>s <strong>de</strong>ux <strong>premier</strong>s<br />
termes <strong>de</strong> <strong>la</strong> liste, le <strong>de</strong>rnier est égal à <strong>la</strong> moyenne <strong>de</strong>s <strong>de</strong>ux <strong>de</strong>rniers termes <strong>de</strong> <strong>la</strong> liste et dont<br />
les autres sont égaux à <strong>la</strong> moyenne <strong>de</strong> trois termes, <strong>la</strong> valeur <strong>de</strong> l’élément au rang j <strong>de</strong> <strong>la</strong> liste<br />
et les valeurs <strong>de</strong>s termes immédiatement avant et après dans <strong>la</strong> liste (j-1 et j+1). On affichera<br />
les nouvelles valeurs contenues dans <strong>la</strong> liste ainsi construite. <strong>Le</strong>s moyennes se calculent à<br />
partir <strong>de</strong>s valeurs <strong>de</strong> <strong>la</strong> liste <strong>initial</strong>es. On admet que <strong>la</strong> longueur <strong>de</strong> <strong>la</strong> liste en argument est<br />
supérieure ou égale à 2.<br />
On pourra construire <strong>de</strong>s listes auxiliaires pour simplifier les calculs.<br />
let rec lisse liste =<br />
let rec calcul liste =<br />
match liste with<br />
|h1::h2::[] -> [(h1+h2)/2]<br />
|h1::h2::h3::t -> ((h1+h2+h3)/3)::calcul (h2::h3::t)<br />
|_ -> failwith "cas impossible"<br />
in<br />
match liste with<br />
|[] -> []<br />
|h::[] -> [h]<br />
|h1::h2::[] -> [(h1+h2)/2;(h1+h2)/2]<br />
|h1::h2::h3::t -> ((h1+h2)/2)::calcul liste;;<br />
let lisse liste =<br />
let rec calcul accumu<strong>la</strong>teur liste =<br />
match liste with<br />
|h1::h2::[] -> accumu<strong>la</strong>teur@[(h1+h2)/2]<br />
|h1::h2::h3::t -> calcul (accumu<strong>la</strong>teur@[(h1+h2+h3)/3]) (h2::h3::t)<br />
in<br />
match liste with<br />
|[] -> []<br />
|h::[] -> [h]<br />
|h1::h2::[] -> [(h1+h2)/2;(h1+h2)/2]<br />
|h1::h2::t -> calcul [(h1+h2)/2] liste;;<br />
let rec lissage_stable liste =<br />
let nouvelle_liste = lisse liste in<br />
if nouvelle_liste = liste then liste<br />
else lissage_stable nouvelle_liste;;
2°/ Ecrire <strong>la</strong> <strong>fonction</strong> puissance comportant 2 variables x et n, <strong>de</strong> manière récursive.<br />
On proposera <strong>de</strong>ux solutions récursives dont l'une terminale.<br />
let rec puissance x n =<br />
match n=0 with<br />
|true -> 1<br />
|_ -> x*puissance x (n-1);;<br />
puissance x n n-1 Critère d'arrêt :<br />
n=0<br />
x*puissance x (n-1) Résultat<br />
16 Retour 5<br />
<strong>Appel</strong> 1 2 4 3 false 16 8 Retour 4<br />
<strong>Appel</strong> 2 2 3 2 false 8 4 Retour 3<br />
<strong>Appel</strong> 3 2 2 1 false 4 2 Retour 2<br />
<strong>Appel</strong> 4 2 1 0 false 2 1 Retour 1<br />
<strong>Appel</strong> 5 2 0 true<br />
let puissance x n =<br />
let rec auxiliaire accumu<strong>la</strong>teur x n =<br />
match n=0 with<br />
|true -> accumu<strong>la</strong>teur<br />
|_ -> auxiliaire x*accumu<strong>la</strong>teur x (n-1)<br />
in<br />
auxiliaire 1 x n;;<br />
auxiliaire x n n-1 n=0 accumu<strong>la</strong>teur x*accumu<strong>la</strong>teur Résultat<br />
16 Retour 5<br />
<strong>Appel</strong> 1 2 4 3 false 1 2 16 Retour 4<br />
<strong>Appel</strong> 2 2 3 2 false 2 4 16 Retour 3<br />
<strong>Appel</strong> 3 2 2 1 false 4 8 16 Retour 2<br />
<strong>Appel</strong> 4 2 1 0 false 8 16 16 Retour 1<br />
<strong>Appel</strong> 5 2 0 true 16
Exercices complémentaires :<br />
• Inversion d'une liste :<br />
let inverse liste =<br />
let rec auxiliaire accumu<strong>la</strong>teur liste =<br />
match liste with<br />
|[] -> accumu<strong>la</strong>teur<br />
|h::t -> auxiliaire (h::accumu<strong>la</strong>teur) t<br />
in<br />
auxiliaire [] liste;;<br />
val inverse : 'a list -> 'a list = <br />
auxiliaire liste h t liste=[] accumu<strong>la</strong>teur h::accumu<strong>la</strong>teur Résultat<br />
[5;4;3;2] Retour 5<br />
<strong>Appel</strong> 1 [2;3;4;5] 2 [3;4;5] false [] [2] [5;4;3;2] Retour 4<br />
<strong>Appel</strong> 2 [3;4;5] 3 [4;5] false [2] [3;2] [5;4;3;2] Retour 3<br />
<strong>Appel</strong> 3 [4;5] 4 [5] false [3;2] [4;3;2] [5;4;3;2] Retour 2<br />
<strong>Appel</strong> 4 [5] 5 [] false [4;3;2] [5;4;3;2] [5;4;3;2] Retour 1<br />
<strong>Appel</strong> 5 [] true [5;4;3;2]
Perfectionnement :<br />
• Ecrire <strong>la</strong> <strong>fonction</strong> récursive terminale calcul_terminal qui applique à une liste <strong>la</strong> <strong>fonction</strong> f<br />
en utilisant un accumu<strong>la</strong>teur.<br />
<strong>Le</strong> calcul d'un résultat intermédiaire s'appliquant à <strong>la</strong> tête <strong>de</strong> <strong>la</strong> liste (nouvelle valeur <strong>de</strong><br />
l'accumu<strong>la</strong>teur) est réalisé avant l'<strong>appel</strong> récursif <strong>de</strong> <strong>la</strong> <strong>fonction</strong> qui s'appliquera au reste <strong>de</strong> <strong>la</strong><br />
liste.<br />
Au <strong>premier</strong> <strong>appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong> l'accumu<strong>la</strong>teur aura pour valeur le résultat quand <strong>la</strong> liste est<br />
vi<strong>de</strong> (<strong>initial</strong>isation <strong>de</strong> l'accumu<strong>la</strong>teur).<br />
let rec calcul_terminal accumu<strong>la</strong>teur liste f =<br />
match liste with<br />
|[] -> accumu<strong>la</strong>teur<br />
|h::t -> calcul_terminal (f h accumu<strong>la</strong>teur) t f ;;<br />
val calcul_terminal : 'a -> 'b list -> ('b -> 'a -> 'a) -> 'a = <br />
• Ecrire <strong>la</strong> <strong>fonction</strong> récursive calcul qui applique à une liste <strong>la</strong> <strong>fonction</strong> f en lui fournissant le<br />
résultat correspondant au cas simple.<br />
<strong>Le</strong> calcul d'un résultat intermédiaire s'appliquant à <strong>la</strong> tête <strong>de</strong> <strong>la</strong> liste sera réalisé quand on<br />
disposera du résultat pour le reste <strong>de</strong> <strong>la</strong> liste.<br />
Au <strong>premier</strong> <strong>appel</strong> <strong>de</strong> <strong>la</strong> <strong>fonction</strong> on fournira le résultat quand <strong>la</strong> liste est vi<strong>de</strong>.<br />
let rec calcul liste f resultat_simple =<br />
match liste with<br />
|[] -> resultat_simple<br />
|h::t -> f h (calcul t f resultat_simple);;<br />
val calcul : 'a list -> ('a -> 'b -> 'b) -> 'b -> 'b = <br />
let s_xpn x n r = x**n +. r;;<br />
val s_xpn : float -> float -> float -> float = <br />
calcul_terminal 0. [1.;2.;3.] (sn 3.);;<br />
- : float = 39.<br />
On calcule <strong>la</strong> somme <strong>de</strong>s puissances <strong>de</strong> 3 pour les exposants présents dans <strong>la</strong> liste.<br />
3**1 + 3**2 + 3**3 = 39<br />
let s_npx x n r = n**x +. r;;<br />
val s_npx : float -> float -> float -> float = <br />
calcul_terminal 0. [1.;2.;3.] (s_npx 3.);;<br />
- : float = 36.<br />
On calcule <strong>la</strong> somme <strong>de</strong>s éléments <strong>de</strong> <strong>la</strong> liste élevés à <strong>la</strong> puissance 3.<br />
1.**3. +. 2.**3. +. 3.**3. = 36.<br />
calcul_terminal 0 [1;2;3] (fun x r -> (x mod 2) + r);;
Calculez <strong>la</strong> somme <strong>de</strong>s entiers <strong>de</strong> <strong>la</strong> liste [9;8;10;7;5;2]<br />
calcul [9;8;10;7;5;2] (+) 0;;<br />
- : int = 41<br />
Concaténez les chaînes <strong>de</strong> caractères <strong>de</strong> <strong>la</strong> liste ["un ";"<strong>de</strong>ux ";"trois "]<br />
calcul_terminal ["un ";"<strong>de</strong>ux ";"trois "] (^) "";;<br />
- : string = "trois <strong>de</strong>ux un "<br />
calcul_terminal (inverse ["un ";"<strong>de</strong>ux ";"trois "]) (^) "";;<br />
- : string = "un <strong>de</strong>ux trois "<br />
• Ecrire <strong>la</strong> <strong>fonction</strong> récursive terminale calcul_conditionnel_terminal qui applique <strong>la</strong><br />
<strong>fonction</strong> f aux éléments d'une liste qui respecte le prédicat p.<br />
let rec calcul_conditionnel_terminal liste f p accumu<strong>la</strong>teur =<br />
match liste with<br />
|[] -> accumu<strong>la</strong>teur<br />
|h::t -> if p h then calcul_conditionnel_terminal (f h accumu<strong>la</strong>teur) t f p<br />
else calcul_conditionnel_terminal accumu<strong>la</strong>teur t f p;;<br />
val calcul_conditionnel _terminal:<br />
'a -> 'b list -> ('b -> 'a -> 'a) -> ('b -> bool) -> 'a = <br />
• Ecrire <strong>la</strong> <strong>fonction</strong> récursive terminale calcul_conditionnel qui applique <strong>la</strong> <strong>fonction</strong> f aux<br />
éléments d'une liste qui respecte le prédicat p.<br />
let rec calcul_conditionnel liste f p resultat_simple =<br />
match liste with<br />
|[] -> resultat_simple<br />
|h::t -> if p h then f h (calcul_conditionnel t f p resultat_simple)<br />
else calcul_conditionnel t f p resultat_simple;;<br />
val calcul_conditionnel : 'a -> 'b list -> ('b -> 'a -> 'a) -> ('b -> bool) -> 'a = <br />
Calculez <strong>la</strong> somme <strong>de</strong>s entiers pairs <strong>de</strong> <strong>la</strong> liste [9;8;10;7;5;2]<br />
calcul_conditionnel 0 [9;8;10;7;5;2] (+) (fun x -> x mod 2 = 0);;<br />
Ecrire une <strong>fonction</strong> entiers_positifs qui construit une liste constituée <strong>de</strong>s entiers positifs<br />
présents dans une liste d'entiers.<br />
let entiers_positifs liste =<br />
calcul_conditionnel liste (fun h liste -> h::liste) (fun x -> x>=0) [];;<br />
let entiers_positifs liste =<br />
let positif x = x>=0 in<br />
let insere h liste = h::liste in<br />
calcul_conditionnel liste insere positif [];;