出于某种原因,我很难想出一种重写此函数的好方法,以便它使用恒定的堆栈空间。大多数关于树递归的在线讨论都是通过使用斐波那契函数并利用该特定问题的属性来作弊的。有没有人对递归的这种“真实世界”(嗯,比斐波那契数列更真实)使用有任何想法?
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)))))
编辑:根据评论中的要求...
用一般术语重述并使用 Scheme——如何重写以下递归模式,使其不消耗堆栈空间或需要对非自调用进行尾调用优化?
(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、浸渍、frobnicate、f、g 或 h 的代数属性的答案。我只想重写递归。
更新:
Rich Hickey为 Clojure添加了一个显式的蹦床函数。