Мне было интересно, есть ли какой-нибудь общий метод для преобразования "нормальной" рекурсии с foo(...) + foo(...)
в качестве последнего вызова хвостовой рекурсии.
Например (scala):
def pascal(c: Int, r: Int): Int = {
if (c == 0 || c == r) 1
else pascal(c - 1, r - 1) + pascal(c, r - 1)
}
Общее решение для функциональных языков для преобразования рекурсивной функции в эквивалент хвостового вызова:
Простым способом является обертка не хвостовой рекурсивной функции в монаде Trampoline
.
def pascalM(c: Int, r: Int): Trampoline[Int] = {
if (c == 0 || c == r) Trampoline.done(1)
else for {
a <- Trampoline.suspend(pascal(c - 1, r - 1))
b <- Trampoline.suspend(pascal(c, r - 1))
} yield a + b
}
val pascal = pascalM(10, 5).run
Таким образом, функция pascal больше не является рекурсивной функцией. Тем не менее, монада Trampoline - это вложенная структура вычислений, которая должна быть выполнена. Наконец, run
является хвостовой рекурсивной функцией, которая проходит через древовидную структуру, интерпретирует ее и, наконец, в базовом случае возвращает значение.
Статья Рунара Бьянарсона по теме батут: без стека Scala со свободными монадами