Возьмет, к примеру, следующая наивная реализация правой складки на схеме:Как достичь хвостовой рекурсии в функциональных программах
(define (fold-rite kons knil clist)
(if (null? clist)
knil
(kons (car clist) (fold-rite kons knil (cdr clist)))))
Это, очевидно, не является кандидатом для устранения хвостового вызова с рекурсивным вызовом fold-rite
должен завершиться до вызова kons
. Теперь, я мог бы быть немного умное и использовать продолжающее прохождение стиля вместо:
(define (fold-rite-cps kons knil clist kontinuation)
(if (null? clist)
(kontinuation knil)
(fold-rite-cps kons knil (cdr clist)
(lambda (x) (kontinuation (kons (car clist) x))))))
Теперь fold-rite-cps
является хвостовой рекурсией, но промежуточные продолжения, построенных во время рекурсии все равно должны храниться где-то. Поэтому, хотя я не могу сдуть стек, я все еще использую примерно столько же памяти, как и в первой версии, и почему-то я чувствую, что сначала собирать массивную кучу продолжений, а затем распутывать их всего одним махом плохой для производительности, хотя вторая версия была на самом деле значительно быстрее на моей машине.
Но если левая складка может работать в постоянном пространстве (за вычетом накопленного значения), а правая справка в списке такая же, как у левой складки на обратном пути, то я полагаю, что должен быть способ реализовать хвостовая рекурсивная правая сфера, которая также может работать в постоянном пространстве. Если да, то как мне это сделать? Получив еще более общую информацию о том, какие способы сделать рекурсивную функцию без хвоста в хвост-рекурсивную, желательно ту, которая может работать в постоянном пространстве (предполагая, что явный цикл может быть написан на императивном языке, который также работает в постоянном пространство)? Я сделал какие-то неправильные предположения?
Хотя я отмечен Scheme и Lisp, меня интересуют решения на любом языке; подходы должны применяться к функциональным программам в целом.
«если левая складка может работать в постоянном пространстве (за вычетом накопленного значения), а правая складка в списке такая же, как у левой складки на обратном пути, то я полагаю, что должен существовать способ реализовать хвост -рекурсивная правая сфера, которая также может работать в постоянном пространстве ». Будете ли вы разочарованы, если окажется, что «сделайте левую складку в перевернутом списке» или какой-нибудь ее вариант? –
Немного :) Мне было интересно, возможно ли это без этого дополнительного шага. Хотя мне просто пришло в голову, что, вероятно, это не так, потому что вы не можете сделать правильную складку, не перейдя в список, так или иначе, так что ... Я должен был подумать об этом больше. – jaymmer
Да, проблема в том, что если вы пытаетесь обработать последний элемент списка, вы должны получить его в * some * point, и для этого потребуется линейный обход. Затем вам понадобится второй, чтобы последний элемент списка, и кажется, что лучший способ иметь это под рукой - это как-то сохранить его, когда вы проходили список, либо в закрытии где-нибудь (когда вы делаете CPS), либо на стек (когда вы разматываете рекурсию). Обратите внимание, что складки в последовательностях произвольного доступа (например, массивы) не имеют этой проблемы; правая сгиб и левая складка выполняются в одно и то же время и пространство. –