我刚开始在我的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新项目一样.
首先,首先查看反向函数的现有实现是一个非常好的主意:
(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-let和seq来检查这coll是非空集合.
然后我使用解构来获取给定集合的第一个元素以及其余部分.
换句话说,我的建设
(if-let [[h & ts] (seq coll)]
(recur ts (conj acc h))
acc)
Run Code Online (Sandbox Code Playgroud)
可以用被改写if,let,first和rest:
(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)
| 归档时间: |
|
| 查看次数: |
112 次 |
| 最近记录: |