`eduction` applies transducers to a collection and provides a lazy, non-caching view of the results. It is useful when transformed values will be reduced rather than retained. Unlike `sequence`, it starts a new transformation loop for each sequential operation, so revisiting results repeats the work. section 7.2.2
Its arguments determine the transformation:
- With no arguments, or with `nil` as its sole argument, it returns `()`. section 7.2.2
- With one supported collection, it provides a sequential view without transformation. section 7.2.2
- With two or more arguments, every argument except the last is a transducer; the last is the collection. Transducers need no explicit `comp`. A nil transducer throws `NullPointerException`; a non-transducer in that position throws `IllegalArgumentException`. section 7.2.2
Compose transformations directly
`(take 2 (eduction (filter odd?) (map inc) (range)))` returns `(2 4)`. The view is lazy, though a request can cause it to produce results in chunks of 32 rather than exactly one item at a time. section 7.2.2
(def cnt1 (atom 0)) (let [res (eduction (map #(do (swap! cnt1 inc) %)) (range 10))] (conj (rest res) (first res)) ; #1 @cnt1) ;; 20 (def cnt2 (atom 0)) (let [res (sequence (map #(do (swap! cnt2 inc) %)) (range 10))] (conj (rest res) (first res)) ; #2 @cnt2) ;; 10
The counters make the caching difference visible: accessing parts of an `eduction` result again runs its transformation again, while the comparable `sequence` result reuses cached work. section 7.2.2
A practical pattern is to pass the view straight to `reduce`: a product-selection example transforms and filters candidates with `eduction`, then reduces them to the best match. Use `sequence` when repeated access should reuse transformed results; use `eduction` when avoiding that cache suits the operation. section 7.2.2 section 7.2
