Reading — step 1 of 5
Learn
~1 min readManaged Mutation
You've seen -> and ->> for threading values through pipelines. Two more variants:
as-> — bind to a name, useful when the threaded value goes in different positions per step:
(as-> 5 x
(* x 2) ; x is 5: 10
(- x 3) ; x is 10: 7
(vector x x)) ; x is 7: [7 7]
some-> and some->> — short-circuit on nil, like Optional chaining:
(some-> user :address :city)
;; equivalent to (when user (when (:address user) (:city (:address user))))
Transducers — separate the what from the where. Same map/filter work on collections, channels, streams.
;; Traditional pipeline allocates intermediate sequences:
(->> coll
(map inc)
(filter odd?)
(take 3))
;; Transducer form — composes the operations into ONE pass:
(def xform (comp
(map inc)
(filter odd?)
(take 3)))
(into [] xform coll) ; apply to a vector
(sequence xform coll) ; apply lazily
(transduce xform + coll) ; apply with a reducing fn
Transducers work on anything reducible — vectors, lists, channels (core.async), even your own types. The transformation is reusable.
For most code, regular pipelines are fine. Transducers shine when:
- You compose the same transform across multiple collections
- You want to avoid intermediate allocation in hot paths
- You're working with channels or other reducible streams
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…