Credence.Pattern.NoMapThenAggregate (credence v0.4.3)

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.