Також є сенс "батут" LISP, як описано у Вікіпедії:
Застосовуваний у деяких реалізаціях LISP, батут - це цикл, який ітеративно викликає функції, що повертають громи. Одного батуту достатньо для вираження всіх контрольних передач програми; програма, висловлена таким чином, є батутною або у "батуті"; перетворення програми на батутний стиль - це батут. Батутні функції можна використовувати для реалізації хвостових рекурсивних викликів функцій на мовах, орієнтованих на стеки
Скажімо, ми використовуємо Javascript і хочемо записати наївну функцію Фібоначчі в стилі продовження-проходження. Причина, через яку ми це зробимо, не має значення - наприклад, переносити схему на JS або грати з CPS, який нам так чи інакше потрібно використовувати для виклику функцій на стороні сервера.
Отже, перша спроба - це
function fibcps(n, c) {
if (n <= 1) {
c(n);
} else {
fibcps(n - 1, function (x) {
fibcps(n - 2, function (y) {
c(x + y)
})
});
}
}
Але, запустивши це n = 25
у Firefox, виникає помилка "Занадто багато рекурсії!". Тепер саме ця проблема (відсутня оптимізація хвостових викликів у Javascript), яка вирішує батут. Замість того, щоб робити (рекурсивний) виклик функції, давайте return
інструкцію (спалахнути), щоб викликати цю функцію, щоб її інтерпретувати в циклі.
function fibt(n, c) {
function trampoline(x) {
while (x && x.func) {
x = x.func.apply(null, x.args);
}
}
function fibtramp(n, c) {
if (n <= 1) {
return {func: c, args: [n]};
} else {
return {
func: fibtramp,
args: [n - 1,
function (x) {
return {
func: fibtramp,
args: [n - 2, function (y) {
return {func: c, args: [x + y]}
}]
}
}
]
}
}
}
trampoline({func: fibtramp, args: [n, c]});
}