01.06.2013 Views

Appel initial : Le premier appel de la fonction.

Appel initial : Le premier appel de la fonction.

Appel initial : Le premier appel de la fonction.

SHOW MORE
SHOW LESS

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 [];;

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!