eduction

added
1.7

ns
clojure.core

type
function

(eduction xform* coll)

Returns a reducible/iterable application of the transducers
to the items in coll. Transducers are applied in order as if
combined with comp. Note that these applications will be
performed every time reduce/iterator is called.

                ;; inc with debugging output
(defn inc-with-print [x]
  (println x)
  (inc x))

(eduction (map inc-with-print) (map inc-with-print) (range 3))
;; 0
;; 1
;; 1
;; 2
;; 2
;; 3
;;=> (2 3 4)

(->> (range 3)
     (map inc-with-print)
     (map inc-with-print))
;; 0
;; 1
;; 2
;; 1
;; 2
;; 3
;;=> (2 3 4)

;; Explanation by freckletonj ---------------------
;; It took me a minute to figure out the documentation and this example.
;; Here's what's going on with the call order:
;;
;; in the `eduction` example, the calling order looks like -
;;     (map #(inc-with-print (inc-with-print %)) (range 3))
;; where as in the `->>` thread example, it looks like -
;;     (map #(inc-with-print %)
;;          (map #(inc-with-print %) (range 3)))
;;
;; So, `eduction` calls the stack of transformers on each element, each time
;;     `->>` calls transformer 1 on a collection, then transformer 2 on the result, etc.

            
                ;; eduction: just run an xform over a collection

(eduction (map inc) [1 2 3])            ; => (2 3 4)
(eduction (filter even?) (range 5))     ; => (0 2 4)

;; several transducers can be given, without using 'comp'
(eduction (filter even?) (map inc)
          (range 5))                    ; => (1 3 5)


            
                ;; This will run out of memory eventually,
;; because the entire seq is realized, 
;; because the head of the lazy seq is retained.
(let 
  [s (range 100000000)] 
  (do (apply print s) (first s)))

;; This iterates through the lazy seq without realizing the seq.
(let 
  [s (eduction identity (range 100000000))] 
  (do (apply print s) (first s)))


            
                ;; Result of eduction is of clojure.core.Eduction type which acts as a lazy
;; collection that re-executes all the steps again and again. This could be
;; useful when you don't want to store the collection separately.
;;
;; Eductions can be efficiently used with reduce and transduce.

(def ed (eduction (map inc-with-print) (map inc-with-print) (range 3)))

(defn identity-with-print [x]
  (println "identity:" x)
  x)

(map identity-with-print ed)
;; 0
;; 1
;; 1
;; 2
;; 2
;; 3
;; identity: 2
;; identity: 3
;; identity: 4
;; => (2 3 4)

(defn sum-with-print [x y]
  (println "sum:" x "+" y)
  (+ x y))

(reduce sum-with-print ed)
;; 0
;; 1
;; 1
;; 2
;; sum: 2 + 3
;; 2
;; 3
;; sum: 5 + 4
;; => 9

(transduce (map identity-with-print) + ed)
;; 0
;; 1
;; identity: 2
;; 1
;; 2
;; identity: 3
;; 2
;; 3
;; identity: 4
;; 1496674214GET/accounts{}
;; => 9