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

(defn recursive-reverse [coll]
  (loop [coll coll]
    (if (< (count coll) 2) '(coll)
      (conj (first coll) (recur (rest coll)))
      )))

编辑

奥斯卡解决方案的输出。它适用于列表,但不适用于 vector 吗?
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)

最佳答案

错误Can only recur from tail position意味着您没有在函数的递归部分中将recur称为最后一个表达式-实际上,在您的代码中conj是最后一个表达式。

使您的代码工作的一些改进:

  • 询问集合是否为空作为基本案例,而不是比较其长度是否小于两个
  • conj接收其第一个参数的集合,而不是元素
  • 最好使用cons而不是conj(根据documentation,它会根据集合的具体类型在不同的位置添加新元素)。这样,如果输入集合是列表或 vector ,则返回的集合将被反转(尽管无论输入集合的类型如何,返回集合的类型始终为clojure.lang.Cons)
  • 请注意,'(coll)是一个包含单个元素(符号coll)的列表,而不是实际的集合
  • 为了正确地反转列表,您需要遍历输入列表并将每个元素附加到输出列表的开头。为此
  • 使用累加器参数
  • 为了利用尾部递归功能,请在函数的尾部位置调用recur。这样,每个递归调用都会占用一定的空间,并且堆栈不会无限增长

  • 我相信这是您的目标:
    (defn recursive-reverse [coll]
      (loop [coll coll
             acc  (empty coll)]
            (if (empty? coll)
                acc
                (recur (rest coll) (cons (first coll) acc)))))
    

    关于recursion - Clojure:只能从尾部位置重现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10864172/

    10-12 22:36