По какой-то причине у меня возникают проблемы с хорошим выбором для перезаписи этой функции, поэтому она использует постоянное пространство стека. Большинство онлайн-дискуссий об обмане рекурсии деревьев используют функцию Фибоначчи и используют свойства этой конкретной проблемы. Есть ли у кого-нибудь идеи для этого "реального мира" (ну, более реального мира, чем серия Фибоначчи) использование рекурсии?
Clojure - интересный случай, поскольку он не имеет оптимизации хвостового вызова, а только хвостовую рекурсию через специальную форму "recur", Это также сильно препятствует использованию изменчивого состояния. У этого есть много ленивых конструкций, включая tree-seq, но я не могу понять, как они могут помочь мне в этом случае. Может ли кто-нибудь поделиться некоторыми методами, которые они выбрали из C, Scheme, Haskell или других языков программирования?
(defn flatten [x]
(let [type (:type x)]
(cond (or (= type :NIL) (= type :TEXT))
x
(= type :CONCAT)
(doc-concat (flatten (:doc1 x))
(flatten (:doc2 x)))
(= type :NEST)
(doc-nest (:level x)
(flatten (:doc x)))
(= type :LINE)
(doc-text " ")
(= type :UNION)
(recur (:doc1 x)))))
edit: по запросу в комментариях...
Пересмотрено в общих чертах и с использованием Схемы - как я могу переписать следующий шаблон рекурсии, чтобы он не занимал пространство стека или не нуждался в оптимизации вызовов не-самих вызовов?
(define (frob x)
(cond ((foo? x)
x)
((bar? x)
(macerate (f x) (frob (g x))))
((thud? x)
(frobnicate (frob (g x))
(frob (h x))))))
Я выбрал раздражающие имена, чтобы отвезти домой, что я ищу ответы, которые не зависят от алгебраических свойств x, macerate, frobnicate, f, g или h. Я просто хочу переписать рекурсию.
UPDATE
Rich Hickey любезно добавил явную функцию батута до Clojure.