Gestion de la m´emoire M´emoire de programme
La pile
A chaque appel de fonction, OCaml alloue un cadre sur la pile.
Chaque cadre de pile stockes (parmi d’autres)
Iles valeurs locales et les param`etres d’un appel de fonction
Iles informations n´ecessaires pour revenir au point de l’appel de la fonction
Quand cet appel de fonction est termin´e, sa m´emoire locale est balay´ee du
sommet de la pile.
Dans l’´evaluation d’une fonction r´ecursive on a un cadre de pile pour chaque
appel r´ecursif.
IPourtant, si on fait une r´ecursion trop profonde on risque d’´epuiser l’espace
disponible pour la pile.
IMais attention, le risque est r´eel seulement si ont fait au moins des dizaines ou
centaines de milliers d’appels r´ecursives.
S. Guerrini (LIPN - Paris 13) Programmation Fonctionnelle f´evrier 2013 71 / 131
Gestion de la m´emoire M´emoire de programme
Appel terminal
Une fonction fapp`ele une fonction get le r´esultat de l’´evaluation de gest
envoy´e tout de suite par f.
Iexemple d’appel terminal :
let f x = if x = 0 then 0 else g x
Iexemple d’appel non-terminal :
letfx=x+gx
Dans le cas d’appel terminal, on n’a plus besoin des valeurs locales de la
fonction fquand on ´evalue g.
Le cadre de fsur la pile peut ˆetre lib´er´e avant d’´evaluer g.
S. Guerrini (LIPN - Paris 13) Programmation Fonctionnelle f´evrier 2013 72 / 131
Gestion de la m´emoire M´emoire de programme
R´ecursion terminale
En anglais, tail recursion.
C’est une fonction r´ecursive, avec tous les appels r´ecursifs `a des positions
terminales.
let rec fold_left f b = function
|[]->b
| h::r -> fold_left f (f b h) r;;
Peut importe la profondeur de r´ecurrence, l’utilisation d’espace reste
constante :
La fonction r´ecursive est ex´ecut´ee comme une boucle d’it´eration !
S. Guerrini (LIPN - Paris 13) Programmation Fonctionnelle f´evrier 2013 73 / 131
Gestion de la m´emoire M´emoire de programme
R´e´ecrire une fonction en r´ecursion terminale
Il est parfois possible de r´e´ecrire une fonction r´ecursive en une fonction
r´ecursive terminale ´equivalente.
let rec somme = function
|[]->0
| hd :: tl -> hd + somme tl;;
let somme ls =
let rec somme_term acc = function
|[]->acc
| hd :: tl -> somme_term (hd + acc) tl
in somme_term 0 ls;;
Normalement, il faut ajouter des param`etres `a la fonction.
IUne fonction r´ecursive terminale correspond `a une version it´erative de la
fonction.
ILes param`etres additionnels sont les donn´ees (l’´etat) modifi´ees `a chaque
it´eration.
let fibonacci n =
let rec fib n =
if (n = 0) then (1,0)
else let (a,b) = fib (n-1)
in (a+b, a)
in fst (fib n);;
let fibonacci n =
let rec fib (a,b) n =
if (n = 0) then (a,b)
else fib (a+b, a) (n-1)
in fst (fib (1, 0) n);;
La r´ecursion terminale permet d’´eviter des d´epassements de pile (en anglais,
stack overflow).
S. Guerrini (LIPN - Paris 13) Programmation Fonctionnelle f´evrier 2013 74 / 131