Fusion
When you chain array operations in pipe, it fuses them into a single loop.
Without fusion:
data [100K] → filter → [50K] → map → [50K] → take(10) → [10]Three passes. Two throwaway arrays.
With fusion:
data [100K] → fused(filter + map + take) → [10]One pass. take(10) breaks the loop after 10 results.
What fuses
Section titled “What fuses”| Operation | Fuseable | |
|---|---|---|
filter, map, flatMap | yes | inlined into the loop |
take, drop | yes | take triggers early exit |
reduce, find, every, some | yes | terminals |
sort, reverse, groupBy, uniq | no | need the full array |
Operations that need the whole array break the chain. Everything before them gets fused and runs first, then the non-fuseable op runs on that result:
pipe( data, A.filter(x => x > 3), // ─┐ segment 1 A.map(x => x * 2), // ─┘ materializes here A.sortBy((a, b) => a - b), // runs on the materialized array A.take(3), // ── segment 2)Mechanics
Section titled “Mechanics”Every function created by dual() carries metadata: _op, _fn, _args. pipe reads these tags and compiles consecutive fuseable ops into a single for loop with inlined predicates. take(n) emits a HALT to break out early.
Your own lambdas pass through unchanged. If nothing is fuseable, pipe just applies functions one after another like you’d expect.