Monday 12 March 2012

Sequence Reductions again

OK that function to get the beginning sections of a list is bugging me.

A neater way is with a list comprehension: work my way down the sequence with (drop ...) until the end (no more (seq ...)) and use these numbers to (take...) sections from the start of the list:

(defn heads [s]
  (for [n (range) :while (seq (drop n s))]
    (take (inc n) s)))


So if I go

user=> (def x '(1 2 3 4 5 6 7 8))
#'user/x


Then I get the initial sections of increasing length:

user=> (heads x)
((1) (1 2) (1 2 3) (1 2 3 4) (1 2 3 4 5) (1 2 3 4 5 6) (1 2 3 4 5 6 7) (1 2 3 4 5 6 7 8))


And it's lazy - I can pass (range) as an argument:

user=> (take 8 (heads (range)))
((0) (0 1) (0 1 2) (0 1 2 3) (0 1 2 3 4) (0 1 2 3 4 5) (0 1 2 3 4 5 6) (0 1 2 3 4 5 6 7))


Now I can make the function that does successively greater reductions like so:

(defn myreduce [f s]
  (map #(reduce f %) (heads s)))


For example:

user=> (reduce + x)
36
user=> (myreduce + x)
(1 3 6 10 15 21 28 36)
user=> (reduce * x)
40320
user=> (myreduce * x)
(1 2 6 24 120 720 5040 40320)