Credence.Pattern.NoMapThenAggregate
(credence v0.4.5)
Copy Markdown
Detects Enum.map/2 immediately followed by a terminal aggregation
like Enum.max/1, Enum.min/1, or Enum.sum/1, which creates an
unnecessary intermediate list.
Why this matters
LLMs default to "transform then aggregate" as the natural functional
decomposition. While readable, the intermediate list from Enum.map
is allocated only to be traversed once and discarded:
# Flagged — two passes, intermediate list allocation
numbers
|> Enum.chunk_every(k, 1, :discard)
|> Enum.map(&Enum.sum/1)
|> Enum.max()
# Better — single pass, no intermediate list
numbers
|> Enum.chunk_every(k, 1, :discard)
|> Enum.reduce(fn chunk, best -> max(Enum.sum(chunk), best) end)For max and min, the fix is Enum.reduce/2 with max/2 or
min/2. For sum, the fix is Enum.reduce/3 accumulating the
result directly.
Flagged patterns
Enum.map(f) piped into or wrapping:
Both pipeline and direct-call nesting forms are detected.