Recursion 在Clojure中递归地反转序列

Recursion 在Clojure中递归地反转序列,recursion,clojure,Recursion,Clojure,我想在Clojure中反转一个序列,而不使用reverse函数,并以递归方式执行 以下是我的想法: (defn reverse-recursively [coll] (loop [r (rest coll) acc (conj () (first coll))] (if (= (count r) 0) acc (recur (rest r) (conj acc (first r)))))) 样本输出: user> (reverse-r

我想在Clojure中反转一个序列,而不使用
reverse
函数,并以递归方式执行

以下是我的想法:

(defn reverse-recursively [coll]
  (loop [r (rest coll)
         acc (conj () (first coll))]
    (if (= (count r) 0)
      acc
      (recur (rest r) (conj acc (first r))))))
样本输出:

user> (reverse-recursively '(1 2 3 4 5 6))
(6 5 4 3 2 1)
user> (reverse-recursively [1 2 3 4 5 6])
(6 5 4 3 2 1)
user> (reverse-recursively {:a 1 :b 2 :c 3})
([:c 3] [:b 2] [:a 1])
问题:

  • 是否有一种更简洁的方法,即无循环/重复
  • 有没有办法不在循环中使用“累加器”参数来实现这一点

  • 参考资料:

    • 你不需要数数。当剩下的序列为空时停止
    • 您不应该预先填充
      acc
      ,因为原始输入可能是空的(而且它包含更多的代码)
    • 解构很酷
    Q1.

    JVM不能优化递归,这是一个递归函数,会直接导致堆栈溢出。因此,在Clojure中,它使用循环/重现。因此,如果不使用一个函数,就无法定义递归。(也可在内部用作功能蹦床。)

    Q2.


    递归函数通过递归,必须是尾部递归。如果正常的递归函数变为尾部递归函数,那么需要携带变量的值作为累加器。

    问题1的答案是肯定的,这就是我对递归koan的回答(我不能告诉你这是否是好的clojure实践)


    在Clojure的当前版本中,有一个名为
    rseq
    的内置函数。对于任何路过的人。

    为了让人精疲力尽,还有一种方法是使用
    进入
    。由于into内部使用了
    conj
    ,因此可按如下方式使用:

    (defn reverse-seq [sss]
      (if (not (empty? sss))
        (conj (reverse-seq (rest sss)) (first sss))
      )
    )
    
    (defn reverse-list 
      "Reverse the element of alist."
      [lst]
      (into '() lst))
    

    关于“使用高阶函数”检查
    (source reverse)
    当这个函数应用map({:a1:b2:c3})时repl abort。从技术上讲,我的问题是“反转一个序列”而不是“反转任何东西,包括一个map”,所以我认为这个问题并不排除它。这里是错误,顺便说一句:
    Clojure>(反向递归{:a1:b2})
    java.lang.UnsupportedOperationException:n此类型不受支持:PersistentArrayMap
    此外,看起来循环/重现对于尾部递归当然是必需的,但在Clojure中它被认为是一种“代码气味”:实际上文章说@noahz“循环/重现不是一种代码味道,但要对它表示怀疑”。我猜他们的意思是,一般来说,更喜欢map、reduce等,但他们不会总是提供解决方案。map序列的顺序不会改变执行。但是顺序应该被实现。我不理解你的评论。“顺序应该被实现?”@noahz,(rev{:A1:B2:C3})->([:C3][:B2][:A1])不一定如此。我的Clojure1.3.0结果是([:B2][:C3][:A1])啊,因为Clojure中的
    PersistentArrayMap
    是无序的,就像
    java.util.HashMap
    ?这是不直观的。我知道。映射通常是不确定的,顺序是知道的。为了按照示例中所示的顺序插入它们,它们必须是必需的。那么,试试这个:
    (递归反向(应用str(seq)(取100000(重复“foo”)))
    很公平,我刚刚谈到了koan的最后一部分,如果没有循环/递归构造,阶乘函数就会溢出。所以我想现在我可以说这不是一个好的做法:)-干杯!这真的很优雅!你可能在尝试吗?:)不,我没有。”递归地反转字符串“是一个非常常见的面试问题。
    rseq
    要求输入序列是可逆的,这使得它通常不合适(不适用于
    cons
    列表,不适用于
    PersistentList
    ,不适用于
    LazySeq
    ,不适用于字符串)。这意味着对可在恒定时间内反转的序列进行优化。
    (defn my-rev [col]
      (loop [ col col
              result []]
            (if (empty? col)
                result
                (recur (rest col) (cons (first col) result)))))
    
    (defn recursive-reverse [coll]
        (if (empty? coll)
            []
            (conj (recursive-reverse (rest coll)) (first coll) )))
    
    (defn reverse-seq [sss]
      (if (not (empty? sss))
        (conj (reverse-seq (rest sss)) (first sss))
      )
    )
    
    (defn recursive-reverse [coll]
      (if (empty? coll)
        ()
        (concat (vector (peek coll)) (recursive-reverse (pop coll )))
      )
    )
    and test:
    user=> (recursive-reverse [1])       
    (1)
    user=> (recursive-reverse [1 2 3 4 5])
    (5 4 3 2 1)
    
    (defn reverse-list 
      "Reverse the element of alist."
      [lst]
      (into '() lst))