Skip to content
Threading Macros and Transducers
step 1/5

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…

Threading Macros and Transducers — Clojure Intermediate