Récursion terminale : ce que coûte l'attente
Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 2 — Le langage OCaml
Énoncé
Ces deux fonctions somment une liste d'entiers. Laquelle consomme de la pile, et pourquoi ? À partir de quelle taille cela se voit-il ?
let rec somme_naive = function [] -> 0 | x :: r -> x + somme_naive r
let somme_acc l =
let rec aux acc = function [] -> acc | x :: r -> aux (acc + x) r in
aux 0 lCorrigé
La différence tient à une addition. Dans somme_naive, l'appel récursif n'est pas la dernière chose faite : au retour, il reste à calculer x + .... Chaque niveau doit donc survivre à son appel, avec sa valeur de x : la pile grandit avec la longueur de la liste, soit en espace.
Dans somme_acc, l'appel aux (acc + x) r est la dernière expression évaluée ; il n'y a rien à faire au retour. On dit l'appel terminal, et le compilateur le transforme en saut : l'espace de pile reste . Les deux fonctions sont en en temps.
La mesure. Sur OCaml 5.4, la pile grandit dynamiquement, et il faut aller loin pour la remplir :
let rec profond n = if n = 0 then 0 else 1 + profond (n - 1)
profond 20 000 000 : ok
profond 40 000 000 : Stack_overflow
Le seuil se déplace d'une machine à l'autre, et l'on peut l'abaisser à volonté par la variable d'environnement OCAMLRUNPARAM. Avec OCAMLRUNPARAM=l=100000, la mesure devient nette :
n = 100 000 : somme_naive leve Stack_overflow, somme_acc = 5000050000
n = 500 000 : somme_naive leve Stack_overflow, somme_acc = 125000250000
somme_acc traverse tout, quelle que soit la limite.
Elle est meilleure en espace, et seulement là. somme_naive se lit en une ligne et se prouve en deux : sa correction est une récurrence immédiate sur la structure de la liste. La version à accumulateur demande de trouver le bon invariant — ici « aux acc l vaut acc plus la somme de l » — et il faut le dire, sans quoi le code devient une astuce. On écrit la version naïve tant que les données sont petites, et l'on passe à l'accumulateur quand on sait qu'elles ne le seront pas. Le chapitre chap:recursivite étudie cette transformation pour elle-même.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.