Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clojure rest and next related

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

like image 256
thlim Avatar asked Nov 01 '11 17:11

thlim


2 Answers

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
like image 134
Arthur Ulfeldt Avatar answered Oct 19 '22 01:10

Arthur Ulfeldt


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.

like image 5
Joost Diepenmaat Avatar answered Oct 18 '22 23:10

Joost Diepenmaat