Monday, February 17, 2014

99 Clojure Problems – 22: Create a List Containing All Integers Within a Given Range

Example:

(deftest p22-range
  (is (= '(4 5 6 7 8 9) (my-range 4 9))))

Solution:

There is a function in clojure.core called 'range' that does the job.

My solution is fairly simple compared to the built-in. It uses a lazy-seq, Clojure's alternative to streams. In the body of the lazy-seq we 'cons' the start element onto either an empty list or onto ourselves via a recursive call. We decide which alternative we choose by comparing the start element with the specified end element. If they are equal we have generated all the values we need and end the recursion.

Delayed computation is the necessary precondition for solving the range problem for arbitrarily large ranges of numbers. Delaying the computation allows us to compute the next value in the range only in the very moment we need it and once we continue with our computation it can be thrown away and the memory it consumed can be freed. In our case, on the JVM, the garbage collector will take care of the last part, unless you hold onto the head of your range somewhere.

I have mentioned lazy-seqs before. But a much better introduction with motivating examples can be found as always in SICP. Rich Hickey did not seem to like the stream approach. What he did like were the benefits of delayed computation. If you compare Clojure's form of laziness to the SICP examples you will find that in SICP a completely separate stream API has been established to allow delayed computation. Clojure's lazy-seq keeps compatibility with the existing higher order functions like map, filter and reduce while offering the same degree of laziness.

Read more about this series.

No comments: