- Use `transient`/`persistent!` for building large collections in tight loops — they mutate in-place then return an immutable result.
- Use `^long` and `^double` type hints on numeric local bindings in hot loops to eliminate autoboxing overhead.
- Use `(into [] xf coll)` with transducer `xf` instead of chained `(map f (filter g coll))` to avoid intermediate lazy sequences.
- Use `reducers` library (`clojure.core.reducers/fold`) for parallel reduction over large collections on multi-core machines.
- Avoid holding the head of a lazy sequence in a `let` binding inside a loop — it prevents the GC from reclaiming already-processed elements.
- Use `aset`/`aget` on primitive Java arrays (`int-array`, `double-array`) in numeric algorithms — they are significantly faster than persistent vectors.
- Profile with `criterium` (`bench` macro) before optimising — measure actual allocation and time rather than guessing hotspots.