Clojure: rest vs. next
It's easy if you have this:
(next '(1))
=> nil
So next
looks at the next thing and if the line is empty it returns nil
instead of an empty seq. This means that it needs to look ahead (to the first item it would return) which makes it not fully lazy (maybe you don't need the next value, but next
wastes the compute time to look ahead).
(rest '(1))
=> ()
rest
doesn't look ahead and just returns the rest of the seq.
Maybe you think, Why even bother using two different things here? The reason is that you normally want to know if there is nothing left in the seq and just return nil
, but in some cases where performance is very important and evaluating one more item could mean tremendous effort you can use rest
.
I now prefer to use next
with recursion, as the escape-evaluation is simpler/cleaner:
(loop [lst a-list]
(when lst
(recur (next lst))
vs
(loop [lst a-list]
(when-not (empty? lst) ;; or (when (seq? lst)
(recur (rest lst))
A case for using rest
, though, would be if you use a collection as a queue or stack. In that case you want your function to return an empty collection when popping or dequeueing the last item.
next
is like (seq (rest ...))
.
rest
will return the remaining piece of a sequence. If that piece of the sequence has not yet been realized, rest
doesn't force it. It won't even tell you if there are more elements left in the sequence.
next
does the same thing but then forces at least one element of the sequence to be realized. So if next
returns nil
, you know there aren't any more elements left in the sequence.
As the page you linked described, next
is stricter than (the new behaviour of) rest
because it needs to evaluate the structure of the lazy cons to know whether to return nil
or a seq.
rest
on the other hand always returns a seq, so nothing needs to be evaluated until you actually use the result of rest
. In other words, rest
is more lazy than next
.