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

时间:2014-03-30 12:56:58

标签: 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)))))

在我的辩护中,它确实有效,但是我发现自己在clojure中做了很多工作,当我需要一个工作列表(如本例中conj新项目时

2 个答案:

答案 0 :(得分:6)

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

(defn reverse [coll]
  (reduce conj () coll))

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

-

但我们假设您的目标是学习递归。我就是这样写的:

(defn rev
  ([coll]
    (rev coll ()))
  ([coll acc]
    (if-let [[h & ts] (seq coll)]
      (recur ts (conj acc h))
      acc)))

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

首先,我使用if-letseq来检查coll是否为非空集合。

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

换句话说,我的构造

(if-let [[h & ts] (seq coll)]
  (recur ts (conj acc h))
  acc)

可以使用ifletfirstrest进行重写:

(if-not (empty? coll)
  (let [h  (first coll)
        ts (rest coll)]
    (recur ts (conj acc h)))
  acc)

这几乎就是你自己写的。

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

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

(defn rev [coll]
  (loop [coll coll
         acc  ()]
    (if-let [[h & ts] (seq coll)]
      (recur ts (conj acc h))
      acc)))

-

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

  • 您应该使用recur;
  • 检查(= (count l) 1);
  • 没有意义
  • 您应该使用empty?代替(= (count orig) 0)

我在你的代码中解决了这两个错误:

(defn rev
  ([l]
   (rev '() l))
  ([l orig]
   (if (empty? orig)
     l
     (recur (conj l (first orig)) (rest orig)))))

答案 1 :(得分:2)

如果您不想将该功能公开给其他arities,请在本地定义和使用它们:

(defn rev [l]
  ((fn rev2 [l orig]
     (if (empty? orig)
       l
       (rev2 (conj (first orig) l) (rest orig))))
   () l))

您可能会发现使用letletfn

更容易
(defn rev [l]
  (letfn [(rev2 [l orig]
             (if (empty? orig)
                l
                (rev2 (conj l (first orig)) (rest orig))))]
    (rev2 () l)))

顺便说一下,......

  • 如果您只是想知道是否存在,请不要计算序列 其中的任何东西。使用seqempty?
  • 摆脱1个元素序列的特殊情况:它并不特殊。
  • ()不需要引用。

当然,我们可以而且应该使用recur而不是对rev2的递归调用,以避免在长序列上吹掉堆栈:

(defn rev [l]
  (letfn [(rev2 [l orig]
             (if (empty? orig)
                l
                (recur (conj l (first orig)) (rest orig))))]
    (rev2 () l)))