Reputation: 3273
Here is an extract from "The Joy of Clojure":
What happens when you create a potentially infinite sequence of integers using iterate, printing a dot each time you generate a new value, and then use either rest or next to return the first three values of the sequence? The difference between rest and next can be seen in the following example:
(def very-lazy (-> (iterate #(do (print .) (inc %)) 1) rest rest rest)) ;=> ..#'user/very-lazy
(def less-lazy (-> (iterate #(do (print .) (inc %)) 1) next next next)) ;=> ...#'user/less-lazy
As shown, the next version printed three dots, whereas the rest version printed only two. When building a lazy seq from another, rest doesn’t cause the calculation of (or realize) any more elements than it needs to; next does. In order to determine whether a seq is empty, next needs to check whether there’s at least one thing in it, thus potentially causing one extra realization. Here’s an example:
(println (first very-lazy)) ; .4
(println (first less-lazy)) ; 4
Here is what I get in my "Cursive IDE" REPL:
(def very-lazy (-> (iterate #(do (print \.) (inc %)) 1)
rest rest rest))
..=> #'user/very-lazy
(def less-lazy (-> (iterate #(do (print \.) (inc %)) 1)
next next next))
..=> #'user/less-lazy
(println (first very-lazy)) ; .4
.4
=> nil
(println (first less-lazy)) ; 4
.4
=> nil
I think I do understand the explanation of the different behaviors, but why is the output the same in my REPL?
Upvotes: 1
Views: 352
Reputation: 84331
The implementation of iterate
changed in Clojure 1.7.0. Prior to 1.7, it was implemented in terms of cons
and lazy-seq
and it exhibited the behaviour described in the fragment of JoC you quoted. Starting with 1.7, it is implemented in terms of a dedicated clojure.lang.Iterate
class which handles rest
and next
in the same way, and so its behaviour is as you discovered at the REPL.
Upvotes: 7