The koan asks for the iteration to begin at zero because range
starts at 0 by default, and that makes for nice looking statement. It is typical and useful in programming to start counting at 0 rather than 1. But, The koan could have been written to start at 1 (or any other number for that matter)
(= (range 1 21) (take 20 (iterate inc 1)))
Here's how iterate is defined
user=> (source iterate)
(defn iterate
"Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects"
{:added "1.0"
:static true}
[f x] (cons x (lazy-seq (iterate f (f x)))))
So, here's how (iterate inc 0)
looks at first
(cons 0, (lazy-seq (iterate inc (inc 0))))
Now when the special lazy-seq element at position 1 (that is, the second position since we count from 0) is first accessed, it is in effect replaced by its expansion.
-- (iterate inc (inc 0))
-> (iterate inc 1)
-> (cons 1, (lazy-seq (iterate inc (inc 1))))
So, the sequence now looks like
-- (cons 0, (lazy-seq (iterate inc (inc 0))))
-> (cons 0, (cons 1 (lazy-seq (iterate inc (inc 1)))))
When the special lazy-seq element at position 2 is first accessed, it is in effect replaced by its expansion.
-- (iterate inc (inc 1))
-> (iterate inc 2)
-> (cons 2, (lazy-seq (iterate inc (inc 2))))
So, the sequence now looks like
-- (cons 0, (cons 1 (lazy-seq (iterate inc (inc 1)))))
-> (cons 0, (cons 1, (cons 2, (lazy-seq (iterate inc (inc 2))))))
Some consequences to be aware, but not typically anything to worry about as a new user
- Any side effects in the body are not executed until accessed, and then only once
- Because you can return a lazy sequence that is not fully realized, beware dependance on dynamic scope, e.g. returning within a
with-
block.
- If you hold a reference to a long/infinite lazy sequence, e.g.
(def numbers (iterate inc 0))
and realize a bunch of them, they will remain in memory. Avoid "holding the head" if this is to be a problem.