I was following The Joy of Clojure and I am puzzled with these 2 statements
(def very-lazy (-> (iterate #(do (print \.) (inc %)) 1) rest rest rest))
(def less-lazy (-> (iterate #(do (print \.) (inc %)) 1) next next next))
accordingly, the output was
(println (first very-lazy)) ; .4
(println (first less-lazy)) ; 4
The book continued to explain that
Grabbing the first element in a lazy seq built with rest causes a realization as expected. But the same doesn’t happen for a seq built with next because it’s already been previously realized. Using next causes a lazy seq to be one element less lazy, which might not be desired if the cost of realization is expensive.
My burning question is why there is an extra dot for 'very-lazy'? My thought was 'print' would print its argument when invoked regardless if next
or rest
.
Thanks
Print actually did exactly the same thing in both cases, it printed only the number. The extra .
was printed by the code inside the list, it just happened to occur at the same time as the printing of the 4
and so it ended up next to it on the screen.
the extra dot is a side effect of the lazy sequence being created on the fly. I would propose a more verbose example to clarify this:
start with two identical lists, both fully-lazy:
esc.core=> (def a (iterate #(do (print "making new element") (inc %)) 1))
#'esc.core/a
esc.core=> (def b (iterate #(do (print "making new element") (inc %)) 1))
#'esc.core/b
then make two more identical lists that start on the fourth element of a
and b
respectively
esc.core=> (def a-partially-realized (-> a rest rest rest))
making new elementmaking new element#'esc.core/a-partially-realised
esc.core=> (def b-more-fully-realized (-> b next next next))
making new elementmaking new elementmaking new element#'esc.core/b-more-fully-realised
esc.core=>
the first three elements of a-partially-realized
have been pre-computed
while the first four elements of b-more-fully-realized
have been pre-computed.
when we read the first element (the fourth in the original list) of a-partially-realized
it has not yet been computed so we will see it being computed.
esc.core=> (print (first a-partially-realized))
making new element4nil
when we do the same to b-more-fully-realised
it will already have the value cached so we just get the result immediately.
esc.core=> (print (first b-more-fully-realized))
4nil
You're missing something important. Count the dots:
user> (def very-lazy (-> (iterate #(do (print \.) (inc %)) 1) rest rest rest))
..#'user/very-lazy
user> (def less-lazy (-> (iterate #(do (print \.) (inc %)) 1) next next next))
...#'user/less-lazy
It always helps to run the code for real instead of just reading a book.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With