Clojure lazy sequence usage

A lazy-seq call just executes the body once the first time it is accessed, then caches and returns the same result whenever it is called again in the future.

If you want to use this to build long (or even infinite) sequences, then you need to recursively nest other lazy-seq calls in the returned sequence. Here’s about the simplest case I can think of:

(defn ints-from [n]
  (cons n (lazy-seq (ints-from (inc n)))))

(take 10 (ints-from 7))
=> (7 8 9 10 11 12 13 14 15 16)

Any (ints-from n) call produces a sequence starting with n, followed by a lazy sequence of (ints-from (inc n)). It’s an infinite list, but that’s not a problem because the lazy-seq ensures that (int-from (inc n)) only gets called when it is needed. You could try exactly the same code without the lazy-seq and you’d get a StackOverflowError very quickly.

lazy-seq is just one of many possible ways to create lazy sequences, and it often isn’t the most convenient. The following are some other interesting/useful ways to create lazy sequences:

; range is an easy way to get an infinite lazy sequence of integers, starting with zero     
(take 10 (range))
=> (0 1 2 3 4 5 6 7 8 9)

; map produces lazy sequences, so the following is lazy 
(take 10 (map #(* % %) (range)))
=> (0 1 4 9 16 25 36 49 64 81)

; iterate is a good way of making infinite sequenes of the form x, f(x), f(f(x))..... 
(take 10 (iterate (partial * 2) 1))
=> (1 2 4 8 16 32 64 128 256 512)

Leave a Comment