Skip to main content

W0070 - Inline Nested List Comprehension

Warning

foo(List) ->
[f(X) || X <- [g(Y) || Y <- List]].
%% ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 💡 weak: W0070: Nested list comprehension can be inlined to avoid intermediate list allocation.

Explanation

This warning detects nested list comprehensions where the outer comprehension iterates over the result of an inner comprehension. The pattern allocates an unnecessary intermediate list that can be eliminated by inlining.

Before

foo(List) ->
[f(X) || X <- [g(Y) || Y <- List]].

After

foo(List) ->
[f(g(Y)) || Y <- List].

Why This Matters

  1. Readability: The inlined form is more concise and directly expresses the intent
  2. Performance & Memory Pressure: The inner comprehension [g(Y) || Y <- List] creates a temporary list that is immediately consumed and discarded

When the Diagnostic Does Not Apply

The transformation is only suggested when the outer variable appears exactly once in the body expression. If the variable appears multiple times, inlining would duplicate the computation:

% NOT transformed - X appears twice, g(Y) would be evaluated twice or require a `begin ... end`  block to first bind the result to a temporary variable
[{X, X + 1} || X <- [g(Y) || Y <- List]].

Notes

Strictly, this changes the order of evaluation, and hence the fix can change semantics. Comparing:

Before

foo(List) ->
[f(X) || X <- [g(Y) || Y <- List]].

After

foo(List) ->
[f(g(Y)) || Y <- List].

In the before case, all evaluations of g(Y) are completed before any evaluations of f(X). In the case after, we have f(g(Y)), so the function calls are interleaved. If g/1 and f/1 are side-effectful and dependent, this change may be problematic. However, it's keeping this ordering which makes the before case more expensive and requires keeping the intemediate list state. Where this order is required, it is suggested to extract the inner comprehension and explicitly bind it first, to make the intention clear, e.g.:

foo(List) ->
Gs = [g(Y) || Y <- List],
[f(X) || X <- Gs].