审查我的初学者clojure反向功能

dag*_*da1 0 clojure

我刚开始在我的clojure旅程中,我想知道是否有人可以在下面的函数中指出我的初学者错误,只是反转列表.我知道已经有一个反向功能所以这纯粹是为了学习.

(defn rev
  ([l]
   (if (= (count l) 1) l (rev '() l)))
  ([l orig]
   (if (= (count orig) 0)
     l
     (rev (conj l (first orig)) (rest orig)))))
Run Code Online (Sandbox Code Playgroud)

在我的辩护中,它确实有效,但我发现自己在clojure中做了很多工作是重载参数列表,以便在我需要一个工作列表时考虑,就像我在这个例子中的conj新项目一样.

Leo*_*tny 6

首先,首先查看反向函数的现有实现是一个非常好的主意:

(defn reverse [coll]
  (reduce conj () coll))
Run Code Online (Sandbox Code Playgroud)

与您的代码的主要区别在于reverse使用高阶函数的现有实现减少了.尽可能使用高阶函数而不是递归是一种很好的做法.

-

但我们假设您的目标是学习递归.这是我写的方式:

(defn rev
  ([coll]
    (rev coll ()))
  ([coll acc]
    (if-let [[h & ts] (seq coll)]
      (recur ts (conj acc h))
      acc)))
Run Code Online (Sandbox Code Playgroud)

让我们仔细看看我的代码.

首先,我使用if-letseq来检查这coll是非空集合.

然后我使用解构来获取给定集合的第一个元素以及其余部分.

换句话说,我的建设

(if-let [[h & ts] (seq coll)]
  (recur ts (conj acc h))
  acc)
Run Code Online (Sandbox Code Playgroud)

可以用被改写if,let,firstrest:

(if-not (empty? coll)
  (let [h  (first coll)
        ts (rest coll)]
    (recur ts (conj acc h)))
  acc)
Run Code Online (Sandbox Code Playgroud)

这几乎就是你自己写的.

最后一件重要的事情是我正在使用recur而不是rev直接调用.它允许clojure编译器执行尾递归优化.

您还应该考虑使用循环而不是创建重载函数,除非您想要将两个参数形成为public:

(defn rev [coll]
  (loop [coll coll
         acc  ()]
    (if-let [[h & ts] (seq coll)]
      (recur ts (conj acc h))
      acc)))
Run Code Online (Sandbox Code Playgroud)

-

因此,您的代码中有很多需要改进的地方.但我只能看到三个真正的错误:

  • 你应该使用recur;
  • 检查是没有意义的(= (count l) 1);
  • 你应该用空?而不是(= (count orig) 0).

在这里,我修复了代码中的这两个错误:

(defn rev
  ([l]
   (rev '() l))
  ([l orig]
   (if (empty? orig)
     l
     (recur (conj l (first orig)) (rest orig)))))
Run Code Online (Sandbox Code Playgroud)