Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 将递归函数转换为使用尾部递归_Clojure_Tail Recursion - Fatal编程技术网

Clojure 将递归函数转换为使用尾部递归

Clojure 将递归函数转换为使用尾部递归,clojure,tail-recursion,Clojure,Tail Recursion,假设我有这样一个函数: user=> (def m {10 5, 5 2, 2 1}) #'user/m user=> (defn hierarchy [x] (when x (cons x (hierarchy (get m x))))) #'user/hierarchy user=> (hierarchy 10) (10 5 2 1) user=> 很明显,这很好,因为叠加深度很小。但是对于这种一般类型的问题,我正在构建一个我想要返回的列表,递归调用总是在cons

假设我有这样一个函数:

user=> (def m {10 5, 5 2, 2 1})
#'user/m
user=> (defn hierarchy [x] (when x (cons x (hierarchy (get m x)))))
#'user/hierarchy
user=> (hierarchy 10)
(10 5 2 1)
user=> 

很明显,这很好,因为叠加深度很小。但是对于这种一般类型的问题,我正在构建一个我想要返回的列表,递归调用总是在cons调用中结束。如何将其转换为尾部递归,以便使用recur而不占用堆栈空间?

阅读累加器

在Clojure中,这个特定的问题可以通过使用
lazy-seq
来解决
lazy seq
延迟计算,因此堆栈溢出(通常)不是问题

(defn hierarchy
  [x]
  (when x
    (lazy-seq
      (cons x (hierarchy (get m x))))))

添加延迟序列:

(defn hierarchy [x] (when x (cons x (lazy-seq (hierarchy (get m x))))))
第一变体

(defn hierarchy* [res x]
  (if-not x
    res
    (recur (conj res x) (get m x))))

(defn hierarchy [x]
  (hierarchy* [] x))
第二


您可以优雅地解决此问题,而无需使用递归:

(defn hierarchy [x]
  (take-while identity (iterate m x)))

对于第一个实现,您不需要定义分离的函数
层次结构*
。在Clojure中,可以为不同数量的参数定义不同的行为。将此标记为正确。我很感激所有的答案,但这与我试图理解的最接近(即使在clojure中有其他可能更好的方法)。也许你可以补充一点,
lazy seq
将递归调用的计算推迟到函数的调用实例退出之后,因此,递归调用实际上永远不会存在于同一堆栈上。“抓住头部”可能仍然会耗尽内存,但这不是因为堆栈溢出。当一个序列一个序列地堆积序列时,仍然会遇到堆栈溢出。示例:
(循环[x(seq一些输入)s nil])(如果s(重复(下一个x)(concat(dostuff(first x))s))
。在实现返回的
s
时,您在
concat
级联上启动了一系列的实现,这可能会导致堆栈溢出。您甚至可以去掉
部分
,直接使用
m
。谢谢,我想知道是否有一种方法可以不用显式递归来实现它。
(defn hierarchy [x]
  (take-while identity (iterate m x)))