I want to implement range function of clojure, why following code won't work ?
(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).
(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 >
.
There are several problems with your code.
As the previous answers point out
(list ret)
is wrong. Replace it with (seq ret)
. Note: To return exactly ()
, not nil
for an empty sequence, use (if (seq ret) (seq ret) ())
. Nil-punning probably makes this needless. concat
is over the top. Use conj
instead. Also,
(my-range 10 0)
loops forever. 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.
EDIT: range
returns a list, not a vector, changed return statement to (if (seq ret) (seq ret) ())
in first implementation of my-range
.
Your code is fine, except for (list ret)
part.
list
function creates new list with given elements (in your example, with single ret
element). If you want to convert your sequential, you should use seq
function instead.
I would also recommend you not to use concat
function here, because its lazy and may cause a StackOwerflowError
producing long sequences.
The rest of your code is fine.
For working example see RedDeckWins's answer .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.