我正在尝试在clojure中实现range函数,但是我的实现返回了一个我无法理解的错误。这是:
(defn implement-range [a b] (
if (= a b)
(conj nil b)
((conj nil a) (implement-range (inc a) b))))
我试图以递归的方式做,但还没有完成,因为我遇到了这个错误:
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.IFn user/implement-range
我认为这是一个我无法看到的括号问题(我是clojure的新手:))。有什么想法吗?
提前感谢您提供任何帮助
编辑:
如果我按这样调用函数,我想返回类似(1 2 3 4)的内容:
(implement-range 1 5)
答案 0 :(得分:2)
你很亲密:
(defn implement-range [a b]
(if (>= a b)
'()
(conj (implement-range (inc a) b) a)))
(implement-range 0 5)
=> (0 1 2 3 4)
首先,主要问题是((conj nil a) (implement-range (inc a) b))))
试图将(conj nil a)
作为函数调用,(implement-range (inc a) b)
作为参数。我不完全确定你在这里尝试做什么,但这绝对不是你想要的。
我做了三处修改:
您需要conj
当前号码到递归调用的结果。这是“不安全的”#34;由于递归调用不在尾部位置,所以递归,但在乱搞时,这并不是什么大问题。如果您打算将其用于实际情况,您会想要使用替代方法。
如果您输入的b
大于a
,则会爆炸。我通过改变基本情况来解决这个问题。
你的基础案例没有任何意义。递归停止后,您将要添加到空列表中。
请注意,只要你看到((
,就会发出一些警钟。这通常是问题的标志,除非您想要表达((comp str inc) 1)
之类的东西;表达式中的第一个表单求值为函数。
答案 1 :(得分:1)
我做了一些研究,发现用这种方式使用conj没有任何意义。所以我想出了这个:
(defn implement-range [a b] (
if (= a b)
b
(flatten (list a (implement-range (inc a) b)))))
因此,如果我使用1 4参数调用该函数,结果将为:
(1 2 3 4)
但是,因为我正在尝试实现像range函数这样的函数,所以它还需要删除最后一个元素。
编辑1
我写的最终功能如下:
(defn implement-range [a b] (
if (= a b)
nil
(remove nil? (flatten (list a (implement-range (inc a) b))))))
编辑2 经过一些更多的研究后,我找到了解决这个问题的另一种方法,代码更少:
(defn new-range [a b]
(take (- b a) (iterate inc a)))
答案 2 :(得分:1)
最简单(也是最经典的)就是这样:
(defn implement-range [a b]
(when (< a b)
(cons a (implement-range (inc a) b))))
user> (implement-range 1 20)
;;=> (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)