首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Clojure:只能从尾部位置重现

Clojure:只能从尾部位置重现
EN

Stack Overflow用户
提问于 2012-06-03 00:47:09
回答 2查看 9.5K关注 0票数 23

我试图递归地反转一个列表,但在运行时得到了Can only recur from tail position。这到底是什么意思,我的代码如何改进才能正常工作?

代码语言:javascript
复制
(defn recursive-reverse [coll]
  (loop [coll coll]
    (if (< (count coll) 2) '(coll)
      (conj (first coll) (recur (rest coll)))
      )))

编辑

Oscar解决方案的输出。它适用于列表,但不适用于向量?

代码语言:javascript
复制
user=> (= (recursive-reverse [1 2 3 4 5]) (recursive-reverse '(1 2 3 4 5)))
false
user=> (= '(1 2 3 4 5) [1 2 3 4 5])
true
user=> (recursive-reverse [1 2 3 4 5])
[1 2 3 4 5]
user=> (recursive-reverse '(1 2 3 4 5))
(5 4 3 2 1)
EN

回答 2

Stack Overflow用户

发布于 2012-06-03 01:18:10

在Clojure中,您只能从尾部位置调用recur。这是语言设计的一部分,也是与JVM相关的限制。

您可以在不使用recur的情况下调用您的函数名(使用递归),并且根据您的程序结构,例如您是否使用惰性序列,您可能不会使堆栈崩溃。但是您最好使用recur,并且使用loop with recur允许您进行一些本地绑定。

下面是一个来自4Clojure.com的示例,其中使用了不带递归的递归。

代码语言:javascript
复制
(fn flt [coll]
  (let [l (first coll) r (next coll)]
    (concat 
      (if (sequential? l)
        (flt l)
        [l])
      (when (sequential? r)
        (flt r)))))
票数 7
EN

Stack Overflow用户

发布于 2012-06-03 03:40:08

使代码正常工作的最简单方法是使用函数名而不是recur

代码语言:javascript
复制
(defn recursive-reverse [coll]
  (loop [coll coll]
    (if (< (count coll) 2) '(coll)
      (conj (first coll) (recursive-reverse (rest coll)))
      )))

当然,这会使调用堆栈变得庞大,并且对于足够大的输入会产生错误。

下面是编写对尾部调用友好的递归-反向版本的另一种方法:

代码语言:javascript
复制
(defn recursive-reverse [s]
  (letfn [
    (my-reverse [s c]
      (if (empty? s)
        c
        (recur (rest s) (conj c (first s)))))]
    (my-reverse s '())))

它从输入列表的头部拉出项目,并将它们添加到累加器列表的头部。

“尾部位置”仅仅意味着recur是函数在返回之前所做的最后一件事。这与你的“自然递归”解决方案不同,在“自然递归”解决方案中,函数在调用自身和返回之间仍有工作要做。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10864172

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档