Transforms#
Transforms describe reusable item pipelines. The compiler lowers them to direct loops without lazy sequences or intermediate collections.
(deftransform paid-totals
(filter paid?)
(map order-total)
(filter positive?))
A transform is compile-time syntax, not a runtime value.
Using A Transform#
Collect results with into:
(let [totals (into [dynamic]int paid-totals orders) :defer]
...)
Reduce without collecting:
(transduce paid-totals + 0 orders)
Run a loop:
(for [total orders :transform paid-totals]
(println total))
Append to an existing dynamic array:
(arr.into! totals paid-totals orders)
Inline transforms use comp:
(into [dynamic]string
(comp
(filter .active?)
(map .name))
users)
A single step can appear directly in any transform position.
Steps#
Supported steps are:
(map f)
(map-indexed f)
(mapcat f)
(filter pred)
(remove pred)
(keep f)
(take n)
(take-while pred)
(drop n)
(drop-while pred)
(distinct)
(distinct-by f)
distinct and distinct-by are available for Data pipelines. Native
pipelines should use arr.distinct or arr.distinct-by.
Callbacks can be named functions, typed inline fn forms, or field selectors
where supported:
(let [minimum 40]
(into [dynamic]int
(comp
(map (fn [order: Order] -> int order.amount))
(filter (fn [amount: int] -> bool (> amount minimum))))
orders))
keep callbacks return [value ok]. map-indexed callbacks receive the
output index and current item.
Sources#
Transforms accept:
- fixed arrays, slices, and dynamic arrays;
- maps, which feed values by default;
Datalists, vectors, sets, and nil;defitercalls;- bounded array producers such as
arr.rangeandarr.repeat.
Use map.entries when a transform needs both keys and values:
(transduce
(map (fn [entry: (map.entry string int)] -> int
(+ (count entry.key) entry.value)))
+ 0
(map.entries scores))
Map loops can keep the key while transforming the value:
(for [key total scores :transform (filter positive?)]
(println key total))
Outputs#
into can create owned dynamic arrays, maps, sets, or vector Data.
Map output expects (map.entry K V) values:
(into map[string]int
(map normalize-entry)
(map.entries source))
transduce accepts +, min, max, a named two-argument reducer, or a typed
inline reducer. Inline reducers can stop early with reduced:
(transduce paid-totals
(fn [sum: int, total: int] -> int
(let [next (+ sum total)]
(if (>= next 100)
(reduced next)
next)))
0
orders)
Ownership#
into returns an owned collection. arr.into! mutates its target.
transduce returns its accumulator. Transform callbacks may borrow their
inputs; managed intermediate Data values are cleaned up when rejected or
replaced by later steps.
Use a direct for loop when the pipeline needs unusual state or when it reads
more clearly.