# Transducers A **transducer** is a reusable transformation pipeline independent of the source or sink. Transducers let you write the "map + filter + take" part once and apply it to any collection, reducer, or channel. Transducers are stateful functions: `(rfn) → rfn'`. They compose, they terminate early, and they don't allocate intermediate collections. ## Quick Start
 # A transducer is built by composing 1-arg forms
def xf [comp
    [map {|x| ($x * 2)}]
    [filter is-even]
    [take 10]]

# Apply it wherever a reducing context is expected
[into @{} xf $xs]                     # conj into a list
[into ^{} xf $xs]                     # add into a set
[transduce xf + 0 $xs]                # fold via a plain fn
[transduce xf [completing +] 0 $xs]   # explicit Reducer wrap 
## The Two Forms `map`, `filter`, `take`, `drop`, and `mapcat` are **arity-overloaded**: - **1-arg** returns a transducer: `[map f]`, `[filter pred?]`, `[take n]` - **2-arg** returns a lazy seq: `[map $xs f]`, `[filter $xs pred?]` The lazy-seq form is covered in [Lazy Sequences](lazy-sequences). Transducers are the 1-arg form composed with `comp`. ## Composing Transducers `comp` composes transducers left-to-right (data flows through them in declaration order):
 def xf [comp
    [filter { ($it % 2) == 0 }]
    [map { $it + 1 }]
    [take 3]]

[into @{} xf @{ 1 2 3 4 5 6 7 8 }]
# => @{ 3 5 7 } 
Note that `comp` runs in source order — `filter` before `map` before `take` — unlike mathematical function composition. ## Applying a Transducer ### `into` — conj into a collection `[into target xf source]` walks `source` through `xf`, conjoining each result element into `target`. Target can be a list literal, a set literal, a map literal, or any existing collection:
 [into @{} xf $xs]                     # list
[into ^{} xf $xs]                     # set (duplicates collapse) 
### `transduce` — fold with a custom reducer
 [transduce xf + 0 $xs]                # sum of transformed elements
[transduce xf str "" $xs]             # concatenate 
The reducer can be a plain 2-arg callable (auto-wrapped via `completing`) or a `%Reducer{:init :step :done}` tagged map. ### `%Reducer` — full reducing protocol A reducing function is a `%Reducer{:init :step :done}` tagged map. The `:init` and `:done` keys may be `nil`. `completing` wraps a plain 2-arg function as a `%Reducer`:
 def sum-reducer %Reducer{
    :init  {|| 0}
    :step  {|acc x| ($acc + $x)}
    :done  {|result| [println "sum was $result"] }
}

[transduce xf $sum-reducer 0 $xs] 
## Early Termination `(take n)` short-circuits any reducing context — not just lazy seqs. Under the hood this uses `%Reduced`:
 # A transducer chain with take inside
def xf [comp [map { $it * 2 }] [take 3]]

# Even when transducing into a sum, the chain stops after 3 elements
[transduce xf + 0 @{ 1 2 3 4 5 6 7 8 9 10 }]
# => 12 (only 1,2,3 were processed: 2 + 4 + 6) 
### `reduced` / `reduced?` / `unreduced` Build your own early-termination step:
 def first-even {|
    set step {|acc x|
        if (is-even x) {
            [reduced x]                       # wrap to terminate
        } {
            $acc
        }
    |
    }
    %Reducer{ :init {|| nil} :step $step :done nil }
|
}

[transduce [filter identity] $first-even nil @{ 1 3 5 6 7 }]
# => 6

[reduced? [reduced 42]]                      # => true
[unreduced [reduced 42]]                     # => 42
[unreduced 42]                                # => 42 (passthrough) 
## Lazy Seq vs Transducer | Aspect | Lazy seq | Transducer | |---|---|---| | Source | Always a collection | Any reducing context | | Sink | Always a list (via `collect`) | List, set, map, sum, custom | | Reuse | Per-call | Reusable across collections | | Early termination | `take n` in the chain | `take n` **or** `%Reduced` in any step | | Best for | One-shot, list-out, readable | Reusable, multi-sink, performance-critical | ## When To Reach For Transducers - The same transformation pipeline is applied to multiple collections or sinks. - The sink is something other than a vector (set, map, sum, custom reducer). - You want explicit early termination across the whole chain. - You're feeding a channel or async task that consumes via a reducing function. For one-shot collection-to-collection transforms where readability matters most, prefer `|>` pipelines (see [Lazy Sequences](lazy-sequences)). ## Examples ### Sum of squares of first 10 evens
 def xf [comp
    [filter { ($it % 2) == 0 }]
    [map { $it * $it }]
    [take 10]]

[transduce xf + 0 [range 0 1000]]
# => 0 + 4 + 16 + ... + 36 (= sum of squares of 0,2,4,...,18) 
### Index a list into a map
 def index-by-name [comp
    [map {|x| %{ :key $x~name :val $x }}]
    (mapcat {|kv| @{ $kv }})])               # unfold into key/val pairs

[into ^{} index-by-name $users]              # set of users by name 
### Compose with multiple sources
 def normalize [comp [map trim] [filter not-empty?] [map lower]]

[into @{} normalize $raw-lines]              # one source
[into @{} normalize $other-lines]            # different source, same pipeline 
## Quick Reference | Form | Purpose | |---|---| | `[map f]` | 1-arg transducer | | `[filter pred?]` | 1-arg transducer | | `[take n]` / `[drop n]` | 1-arg transducer | | `[mapcat f]` | 1-arg transducer | | `[comp xf1 xf2 ...]` | Compose transducers | | `[into target xf source]` | Conj into a collection | | `[transduce xf rfn init source]` | Fold via reducer | | `[completing f]` | Wrap a plain fn as `%Reducer` | | `[reduced x]` / `[reduced? x]` / `[unreduced x]` | Early-termination protocol |