Так, деякі мови та компілятори перетворять рекурсивну логіку в нерекурсивну логіку. Це відоме як оптимізація хвостових викликів - зауважте, що не всі рекурсивні дзвінки можуть бути оптимізовані. У цій ситуації компілятор розпізнає функцію форми:
int foo(n) {
...
return bar(n);
}
Тут мова здатна визнати, що результат, що повертається, є результатом іншої функції та змінить виклик функції з нового кадру стека в стрибок.
Зрозумійте, що класичний факторіальний метод:
int factorial(n) {
if(n == 0) return 1;
if(n == 1) return 1;
return n * factorial(n - 1);
}
це НЕ хвіст виклик optimizatable з інспекції , необхідної на повернення.
Щоб зробити цей заклик оптимізованим,
int _fact(int n, int acc) {
if(n == 1) return acc;
return _fact(n - 1, acc * n);
}
int factorial(int n) {
if(n == 0) return 1;
return _fact(n, 1);
}
Компіляція цього коду з gcc -O2 -S fact.c
(-O2 необхідна для включення оптимізації в компіляторі, але при більшій оптимізації -O3 людині важко читати ...)
_fact:
.LFB0:
.cfi_startproc
cmpl $1, %edi
movl %esi, %eax
je .L2
.p2align 4,,10
.p2align 3
.L4:
imull %edi, %eax
subl $1, %edi
cmpl $1, %edi
jne .L4
.L2:
rep
ret
.cfi_endproc
Ви можете бачити в сегменті .L4
, jne
а не a call
(який виконує виклик підпрограми з новим фреймом стека).
Зверніть увагу, що це було зроблено з C. Оптимізація виклику хвостів у Java є важкою і залежить від впровадження JVM - хвоста-рекурсія + java та хвоста-рекурсія + оптимізація - це гарні набори тегів для перегляду. Ви можете знайти інші мови JVM здатні оптимізувати хвостову рекурсію краще (спроба Clojure (який вимагає повторювався для оптимізації хвостового виклику), або Скелі).
return recursecall(args);
для рекурсії, більш складні речі можливі, створивши явний стек і ліквідувавши його, але я сумніваюся, що вони будуть