Skip to content

Instantly share code, notes, and snippets.

@ithayer
Last active August 29, 2015 14:05
Show Gist options
  • Save ithayer/98221873f2444409a318 to your computer and use it in GitHub Desktop.
Save ithayer/98221873f2444409a318 to your computer and use it in GitHub Desktop.
Transducers Examples
;; Example of reducing fn that computes sufficient
;; statistics for a mean.
=> (defn mean-reducer [memo x]
(-> memo
(update-in [:sum] + x)
(update-in [:count] inc)))
=> (reduce mean-reducer {:sum 0 :count 0} (range 10))
{:count 10, :sum 45}
;; A crude "transducer" that accepts a reducing function 'f1'
;; and returns a new reducing function that will have
;; 'input' incremented.
=> (defn increment-transducer [f1]
(fn [result input] ;; A transducer returns a reducing fn.
(f1 result ;; That reducing fn will still call 'f1',
(inc input)))) ;; but only after it increments the input.
=> (reduce (increment-transducer mean-reducer)
{:sum 0 :count 0}
(range 10))
{:count 10, :sum 55}
;; Source of the new arity of the 'map' function.
(defn map
([f] ;; When called with a single argument,
(fn [f1] ;; map returns a transducer that accepts a reducing function.
(fn ;; Like our crude transducer, this transducer returns
;; a reducing function,
([] (f1))
([result] (f1 result))
([result input] ;; and this arity does the same as what ours did.
(f1 result (f input)))
([result input & inputs]
(f1 result (apply f input inputs))))))
;; No need for an explicit 'increment-transducer' function, it
;; can be created by 'map'.
=> (reduce ((map inc) mean-reducer)
{:sum 0 :count 0}
(range 10))
{:count 10, :sum 55}
;; Same result without transducers.
=> (->> (range 10)
(map inc)
(reduce mean-reducer
{:sum 0 :count 0}))
{:count 10, :sum 55}
;; Some examples from the launch announcement.
;; Use 'sequence' to return a new transduced sequence.
=> (sequence (map inc) (range 10))
(1 2 3 4 5 6 7 8 9 10)
;; Use 'transduce' like 'reduce'.
=> (transduce (map inc) mean-reducer {:sum 0 :count 0} (range 10))
{:count 10, :sum 55}
;; Note that one important difference between 'transduce' and 'reduce'
;; is the behavior when an initial value is not passed.
;; 'transduce' - calls the reducing function (eg: 'mean-reducer' above)
;; with no args to generate the initial value
;; 'reduce' - starts the reducing function on the first two values
;; of the sequence
;; Use 'into' to populate a new data structure without an intermediate
;; sequence.
=> (into [] (map inc) (range 10))
[1 2 3 4 5 6 7 8 9 10]
;; Examples of 'transducer' composition, note the order of invocation.
=> (sequence (comp (filter even?) (map inc)) (range 10))
(1 3 5 7 9)
=> (sequence (comp (map inc) (filter even?)) (range 10))
(2 4 6 8 10)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment