Tail-call optimization reuses the current call’s stack space when the final operation is another function call. Elixir, through Erlang, can treat that call like a jump instead of pushing a new stack frame, so tail-recursive functions can handle arbitrarily large iterations without consuming additional memory. section 3.4.1 section 3.4.2
A call is eligible for this optimization when:
- The function’s final operation calls another function or calls itself. section 3.4.2
- The caller returns the callee’s result directly, allowing execution to jump without preserving additional caller state. section 3.4.2
- Recursive work carries intermediate results in arguments, such as current_sum, rather than performing more computation after the recursive call. section 3.4.2
Tail-recursive list summation
ListHelper.sum/1 initializes the accumulated value, while private do_sum/2 handles the recursion. For a nonempty list, it computes a new sum and calls itself with the remaining tail; for an empty list, it returns the accumulator. Both [1, 2, 3] and [] produce the expected results.
Not every recursive function is tail recursive. In head + sum(tail), the addition remains after the recursive call returns; likewise, 1 + another_fun(...) prevents the call from being the final operation. Tail recursion is therefore a structural property of the last expression, not merely a synonym for recursion.


