(defn some
"Returns the first logical true value of (pred x) for any x in coll,
else nil. One common idiom is to use a set as pred, for example
this will return :fred if :fred is in the sequence, otherwise nil:
(some #{:fred} coll)"
{:added "1.0"
:static true}
[pred coll]
(when-let [s (seq coll)]
(or (pred (first s)) (recur pred (next s)))))
They are quite similar, but next looks at the result of the ânextâ thing (so it may be evaluated) and returns nil, while rest just returns the ânextâ thing. So usually next is better, but IRL they might be equivalent.
next and rest only differ in how they respond to an empty sequence, next returns nil, rest returns an empty list. (in particular: clojure.lang.PersistentList/EMPTY).
on the next iteration seq would return nil either way, but it needs to do more work in the second case. It would have to call the seq method on that empty list, which then returns nil.
(def
^{:arglists '([coll])
:tag clojure.lang.ISeq
:doc "Returns a seq of the items after the first. Calls seq on its
argument. If there are no more items, returns nil."
:added "1.0"
:static true}
next (fn ^:static next [x] (. clojure.lang.RT (next x))))
Honestly Iâm not sure, I always have a hard time remembering which is which to begin with. Given that Clojure is quite systematic with its nil-punning they are usually interchangeable.
Looking at clojure.core it seems Rich uses rest a few times when passing the result to map or concat, which kind of makes sense because you clearly expect something seqable there, but OTOH map and concat will start by calling seq first, so next would work just fine and might even be a tiny tad faster.
Does anyone have a rule of thumb of when to use which one, or even how to remember which is which?
So rest always returns a sequence, whereas next returns nil rather than an empty sequence. I learned something today!
user=> (rest [1])
()
user=> (next [1])
nil
Iâve previously just used (rest xs) in my own code, even when iterating. But with next, Iâll be able to to that more smoothly! I re-implemented map (no lazyness) with this logic, which let me avoid some null checks.
I tried re-implementing map with both, and the next version was 20 % faster. Didnât expect that!
first of all i want to thank everyone for answering my question so quickly!
nevertheless i have to say that i am still very much confused about seq, rest and next
now in order to explain where all of this confusion is coming from, i should perhaps say, that i have read the book âthe joy of clojure, 2nd editionâ ( or at least large parts of it ) and to be honest i still think that it is a fantastic book. having said that, i now feel like i may have taken some things from the book without doing sufficient testing on my own.
so for example in my mind (next s) was really like (seq (rest s)) and also i took away from the book, that rest is more lazy than next.
so then i just happened to write a piece of code that used the some function, and sometimes i do look at the source from clojure itself so i found that it did use the seq check for the condition but then also next for the recursive part. so i thought to myself, well is that not like calling seq too often?
so i thought well, why not register at clojureverse and ask about this, and i am really
glad i did, because the answers that i got made me realize, that some of the preconceived ideas i had formed because of the book i mentioned, really do need some re-evaluation.
alright, so first of all i did search for the topics of seq, next and rest in the book again
( with manning you do get the pdf version as well, so that came in really handy!)⊠in any
case in the book you find for example under chapter 3.2 ânil pun with careâ the following:
Second, rest is used instead of next to consume the sequence on the recursive call.
Although theyâre nearly identical in behavior, rest can return a sequence thatâs either
empty or not empty (has elements) C , but it never returns nil . On the other hand,
next returns a seq of the rest , or (seq (rest s)) , and thus never returns an empty
sequence, returning nil in its place. Itâs appropriate to use rest here because youâre
using seq explicitly in each subsequent iteration.
also under chapter 6.3.2 âUnderstanding the lazy-seq recipeâ there is a little box
titled next vs. rest in which you can find the following code example:
so i tried that out as well BUT!!! it did not come out as expected. and
it seams i was not the only one to notice this:
now in the comments i found:
I would think the advice would stand because next is still one item less lazy than rest. â webappzero Nov 3 '17 at 20:58
but i have a really hard time to even come up with a good example for showing this difference in lazy behavior.
so⊠some, seq, rest, next??? clojure idiom for doing nil-pun iteration like stuff,⊠i am
totally lost!
if anyone could help shed some more light on this matter i would really
appriciate it, because it seams to me that the matter at hand is pretty
important, since it seams so basic,âŠ
As that SO answer says, the definition of iterate changed between Clojure 1.6 and 1.7. If you look at the behavior of the 1.6 version of iterate, you see the difference in laziness:
user=> (defn iter [f x] (cons x (lazy-seq (iter f (f x)))))
#'user/iter
user=> (def very-lazy (-> (iter #(do (print \.) (inc %)) 1) rest rest rest))
..#'user/very-lazy ; only two dots here
user=> (def less-lazy (-> (iter #(do (print \.) (inc %)) 1) next next next))
...#'user/less-lazy ; three dots here
user=> (println (first very-lazy))
.4 ; forces one more iteration
nil
user=> (println (first less-lazy))
4 ; that iteration had already been done
nil
user=>
java -version
openjdk version "11.0.4" 2019-07-16
OpenJDK Runtime Environment (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3)
OpenJDK 64-Bit Server VM (build 11.0.4+11-post-Ubuntu-1ubuntu218.04.3, mixed mode, sharing)
now i still have to think about many of the things involved, ( i find that this does raise a lot of very interesting questions :-))⊠so i really can not say much about what this means,⊠but i guess i just wanted to keep anyone interested in this âin the loopâ
i have been meaning to watch this video now in like forever,⊠seams like a very interesting talk!.. but i do think that this is really a different subject / topic,⊠but an interesting one :-)⊠so you do get a heart from me