在clojure返回错误中实现范围函数

时间:2018-03-04 22:05:48

标签: clojure functional-programming

我正在尝试在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)

3 个答案:

答案 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)