Clojure,实施范围,为什么这个解决方案不起作用

时间:2014-08-15 20:48:43

标签: clojure

我想实现clojure的范围函数,为什么以下代码不起作用?

(fn [low high]
  (loop[low low
        ret []]
    (if(= low high)
    (list ret)
    (recur (inc low) (concat ret [low])))))

3 个答案:

答案 0 :(得分:4)

我在下面给出了两个正确的实现。你的问题是当你调用(list ret)时,你正在以另一个顺序包装你的累加器(已经是一个列表)。

(defn my-range [low high]
  (loop [low low
        ret []]
    (if (= low high)
      (seq ret)
      (recur (inc low) (conj ret low)))))

(defn my-range2 [low high]
  (take-while
    (partial > high)
    (iterate inc low)))

修改:range在其返回的序列中不包含上限参数,partial中的my-range2>=更改为>

答案 1 :(得分:2)

您的代码存在一些问题。

如先前的答案所指出的那样

  • (list ret)错了。将其替换为(seq ret)。注意:要准确返回(),而不是nil为空序列,请使用(if (seq ret) (seq ret) ())。没有惩罚可能使这不必要。
  • concat超过了顶部。请改用conj

另外,

  • 防止失控:(my-range 10 0)永远循环。将=替换为>=

进行这些更改,

(defn my-range [low high]
  (loop [low low, ret []]
    (if (>= low high)
      (if (seq ret) (seq ret) ())
      (recur (inc low) (conj ret low)))))

剩下的问题是这不是懒惰的:它在返回之前开发整个向量。例如,

(take 5 (my-range 42 (java.lang.Integer/MAX_VALUE)))

......似乎需要永远,尽管你只需要五个元素。

是一个简单的懒惰版本
(defn my-range [low high]
  (lazy-seq
    (if (>= low high) () (cons low (my-range (inc low) high)))))

然后

(take 5 (my-range 42 (java.lang.Integer/MAX_VALUE)))
;(42 43 44 45 46)

......立竿见影。

RedDeckWins's my-range2同样适用,而且更整洁。

编辑:range(if (seq ret) (seq ret) ())的第一个实现中返回一个列表,而不是向量,将return语句更改为my-range

答案 2 :(得分:1)

您的代码没有问题,(list ret)部分除外。

list function使用给定元素创建新列表(在您的示例中,使用单个ret元素)。如果您想转换顺序,则应使用seq function代替。

我还建议你不要在这里使用concat function,因为它很懒,可能导致产生StackOwerflowError长序列。

其余代码没问题。

有关工作示例,请参阅RedDeckWins's answer