;; inside understand
; http://elbenshira.com/blog/understanding-transducers/
; reducing fn: result, input -> result
(conj [1 2 3] 4)
;=> [1 2 3 4]
(+ 10 1)
;=> 11
; transducer (xform): transform from one reducing fn to another
; (result, input -> result) -> (result, input -> result)
;; how to use
; https://clojure.org/reference/transducers
; https://www.astrecipes.net/blog/2016/11/24/transducers-how-to/
(filter odd?) ;; returns a transducer that filters odd
(map inc) ;; returns a mapping transducer for incrementing
(take 5) ;; returns a transducer that will take the first 5 values
; comp: right-to-left, but builds a transformation stack runs left-to-right ~ thread macro
(def xf
(comp
(filter odd?)
(map inc)
(take 5)))
; equivalent
(->> coll
(filter odd?)
(map inc)
(take 5))
;; transduce will immediately (not lazily) reduce over coll
;; with the transducer xform applied to the reducing function f
(transduce xform f coll)
(transduce xform f init coll)
(def xf (comp (filter odd?) (map inc)))
(transduce xf + (range 5))
;=> 6
(transduce xf + 100 (range 5))
;=> 106
;; eduction returns a reducible/iterable
(def iter (eduction xf (range 5)))
(reduce + 0 iter)
;=> 6
;; into: transducer coll -> coll
(into [] xf (range 1000))
(sequence xf (range 1000))
;; creating transducers
; https://dev.to/greencoder/build-your-own-transducer-and-impress-your-cat---part-1-mhp
(fn [xf]
(fn ([] ...) ; init
([result] ...) ; completion
([result input] ...))) ; step
(def inc-transducer
(fn [rf]
(fn ([] (rf)) ; 0-arity aka 'the useless'
([result] (rf result)) ; 1-arity aka 'the flusher'
([result input] (rf result (inc input)))))) ; 2-arity aka 'the doer'
(into [] inc-transducer (list 4 5 6))
; => [5 6 7]
; idiomatic way:
; (into [] (map inc) (list 4 5 6))
;; with core.async
; https://eli.thegreenplace.net/2017/reducers-transducers-and-coreasync-in-clojure/
; https://malcolmsparks.com/posts/transducers.html