简体   繁体   English

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

[英]Clojure, implement range, why this solution doesn't work

I want to implement range function of clojure, why following code won't work ? 我想实现clojure的作用域功能,为什么以下代码不起作用?

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

I've given two correct implementations below. 我在下面给出了两个正确的实现。 Your problem is you were wrapping your accumulator, which was already a list, in another sequence when you called (list ret). 您的问题是您在调用(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)))

Edit: range doesn't include the upper limit parameter in its returned seq, changed partial in my-range2 from >= to > . 编辑: range在返回的seq中不包含上限参数,将my-range2 partial>=更改为>

There are several problems with your code. 您的代码有几个问题。

As the previous answers point out 如先前的答案所指出

  • (list ret) is wrong. (list ret)是错误的。 Replace it with (seq ret) . 将其替换为(seq ret) Note: To return exactly () , not nil for an empty sequence, use (if (seq ret) (seq ret) ()) . 注意:要完全返回() ,而不是nil表示空序列,请使用(if (seq ret) (seq ret) ()) Nil-punning probably makes this needless. 零敲打可能使这不必要。
  • concat is over the top. concat在顶部。 Use conj instead. 使用conj代替。

Also, 也,

  • Guard against runaway: (my-range 10 0) loops forever. 防止失控:( (my-range 10 0)永远循环。 Replace = with >= . =替换= >=

Making these changes, 进行这些更改,

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

The remaining problem is that this is not lazy: it develops the whole vector before returning. 剩下的问题是,这并不懒惰:它会在返回之前生成整个向量。 For example, 例如,

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

... seems to take forever, though you only want five elements. ...似乎要花很多时间,尽管您只想要五个元素。 A simple lazy version is 一个简单的懒惰版本是

(defn my-range [low high]
  (lazy-seq
    (if (>= low high) () (cons low (my-range (inc low) high)))))

Then 然后

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

... is immediate. ...是立即的。

RedDeckWins's my-range2 does just as well, and is neater. RedDeckWins的my-range2也一样,而且更整洁。

EDIT: range returns a list, not a vector, changed return statement to (if (seq ret) (seq ret) ()) in first implementation of my-range . 编辑: range返回列表,而不是向量,在my-range第一个实现中将return语句更改为(if (seq ret) (seq ret) ())

Your code is fine, except for (list ret) part. 您的代码很好,除了(list ret)部分。

list function creates new list with given elements (in your example, with single ret element). list函数创建具有给定元素的新列表(在您的示例中,具有单个ret元素)。 If you want to convert your sequential, you should use seq function instead. 如果要转换顺序,则应改用seq函数

I would also recommend you not to use concat function here, because its lazy and may cause a StackOwerflowError producing long sequences. 我也建议您不要在这里使用concat函数 ,因为它比较懒,并且可能会导致StackOwerflowError生成长序列。

The rest of your code is fine. 您的其余代码很好。

For working example see RedDeckWins's answer . 有关工作示例,请参见RedDeckWins的答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM