Justement si, une optimisation sur la pile d'appel car il estime qu'on risque de partir en stack overflow, ou qu'on perd trop de temps en changement de contexte.
Je ne vois pas trop cela dans son pseudo-code : il teste si l'appel est récursif et il empile, puis ne dépile que dans le cas contraire. On risque le débordement de pile. Mais c'est peut être moi qui ne comprend pas ce qu'il veut faire, je trouve qu'il ne s'exprime pas clairement.
Après ce n'est pas tant une question d'optimisation, contrairement à ton exemple. Pour moi, une fonction récursive terminale doit être compilée en consommant un espace constant sur la pile, sinon le compilateur est buggé. Je ne considère pas cela comme une optimisation mais comme une obligation sur le schème de compilation à utiliser.
Ton exemple est simple à écrire comme il faut, sans compter sur une optimisation du compilateur. Je le fais en OCaml :
letcountn=letshowi=ifimod10_000=0then(print_inti;print_newline())inletrecloopacc=function|0->acc(* ici l'appel récursif est terminal *)|i->showi;loop(acc+1)(i-1)inloop0n;;
Le code récursif, correctement compilé, est équivalent à celui-ci avec un boucle for :
Quelque soit le code choisi, il n'y a aucun risque de saturer la pile.
Je ne dis pas qu'il faut faire du récursif, souvent on peur remplacer par de l'itératif sans que ça alourdisse le code, mais remplacer tout appel récursif, juste par principe, avant même qu'un problème ait été levé, le tout via des solutions lourdes et compliqué rends rapidement le code visé difficile à maintenir.
Comme dit par uso dans le fil, cela dépend du langage utilisé et de ses idiomes. L'écriture de code récursif est tout un art. En OCaml, la plupart du temps on ne peut écrire du code que de manière récursive. Par exemple, la fonction qui itère une autre fonction (par effet de bords) sur les listes ne peut être écrite qu'ainsi :
letreciterf=function|[]->()|hd::tl->fhd;iterftl;;
Exemple d'usage :
List.iterprint_int[1;2;3];;(* retour de l'appel *)123
La fonction est terminale récursive et aura un code compilé équivalent à celui avec une boucle for ou while d'un langage impératif.
Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.
[^] # Re: Loupé
Posté par kantien . En réponse au lien La récursivité sur linuxfr. Évalué à 3.
Je ne vois pas trop cela dans son pseudo-code : il teste si l'appel est récursif et il empile, puis ne dépile que dans le cas contraire. On risque le débordement de pile. Mais c'est peut être moi qui ne comprend pas ce qu'il veut faire, je trouve qu'il ne s'exprime pas clairement.
Après ce n'est pas tant une question d'optimisation, contrairement à ton exemple. Pour moi, une fonction récursive terminale doit être compilée en consommant un espace constant sur la pile, sinon le compilateur est buggé. Je ne considère pas cela comme une optimisation mais comme une obligation sur le schème de compilation à utiliser.
Ton exemple est simple à écrire comme il faut, sans compter sur une optimisation du compilateur. Je le fais en OCaml :
Le code récursif, correctement compilé, est équivalent à celui-ci avec un boucle
for:Quelque soit le code choisi, il n'y a aucun risque de saturer la pile.
Comme dit par uso dans le fil, cela dépend du langage utilisé et de ses idiomes. L'écriture de code récursif est tout un art. En OCaml, la plupart du temps on ne peut écrire du code que de manière récursive. Par exemple, la fonction qui itère une autre fonction (par effet de bords) sur les listes ne peut être écrite qu'ainsi :
Exemple d'usage :
La fonction est terminale récursive et aura un code compilé équivalent à celui avec une boucle
forouwhiled'un langage impératif.Sapere aude ! Aie le courage de te servir de ton propre entendement. Voilà la devise des Lumières.