Рассмотрим простую функцию, которая добавляет первые N целых чисел. (например, sum(5) = 1 + 2 + 3 + 4 + 5 = 15
).
Вот простая реализация JavaScript, которая использует рекурсию:
function recsum(x) {
if (x===1) {
return x;
} else {
return x + recsum(x-1);
}
}
Если бы вы позвонили recsum(5)
, интерпретатор JavaScript оценил бы это так:
recsum(5)
5 + recsum(4)
5 + (4 + recsum(3))
5 + (4 + (3 + recsum(2)))
5 + (4 + (3 + (2 + recsum(1))))
5 + (4 + (3 + (2 + 1)))
15
Обратите внимание, как каждый рекурсивный вызов должен завершиться, прежде чем интерпретатор JavaScript начнет выполнять вычисление суммы.
Вот хвосто-рекурсивная версия той же функции:
function tailrecsum(x, running_total=0) {
if (x===0) {
return running_total;
} else {
return tailrecsum(x-1, running_total+x);
}
}
Вот последовательность событий, которые произошли бы, если бы вы вызвали tailrecsum(5)
(что фактически будет tailrecsum(5, 0)
из-за второго аргумента по умолчанию).
tailrecsum(5, 0)
tailrecsum(4, 5)
tailrecsum(3, 9)
tailrecsum(2, 12)
tailrecsum(1, 14)
tailrecsum(0, 15)
15
В случае хвостовой рекурсии, с каждой оценкой рекурсивного вызова обновляется running_total
.
Примечание. В исходном ответе использовались примеры из Python. Они были изменены на JavaScript, поскольку современные интерпретаторы JavaScript поддерживают оптимизацию хвостового вызова , а интерпретаторы Python - нет.