Question

"Iteration provides an infinite lazy sequence"

 (= (range 20) (take 20 (iterate inc 0)))

So my question is why it start from 0 instead of 1 ? How to understand the laziness here ?

Was it helpful?

Solution 2

clojure.core/iterate takes two arguments:

  1. the fn to apply to the last element in the sequence. When applied, it should produce the next element in the sequence

  2. the initial value of the sequence

(iterate inc 0) has 0 as the initial element of the sequence.

(take 1 (iterate inc 0)) ;; (0)

OTHER TIPS

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.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top