ELIXIR / CHAPTER 09
Recursive list processing
AdvancedWrite complete list clauses and pass evolving state explicitly.
By the end of this chapter
- Define a terminating empty case
- Recur on the remaining tail
- Carry an accumulator without mutable state
The idea
Enter with list patterns and function clauses understood. A recursive function can process a list by handling [] as a base case and [head | tail] as a step. Passing tail to the next call makes progress through a finite list. Elixir does not mutate the original list during this traversal, so any evolving state must be represented as an argument to the recursive function.
An accumulator records completed work, such as a running sum or count. A public wrapper can choose its initial value while a private helper handles recursion. In a tail-recursive form, the recursive call is the last operation of the clause; no pending addition remains after it returns. Correctness still depends on the base case and update rule. Tail position does not rescue recursion that never reaches a terminating case.
defmodule Totals do
def sum(values), do: sum(values, 0)
defp sum([], acc), do: acc
defp sum([h | t], acc), do: sum(t, acc + h)
end
IO.inspect(Totals.sum([3, 2, 6]))11
The accumulator progresses through zero, three, five, and eleven. The empty-list clause returns the completed sum.
Try it yourself
Write a recursive count function that returns zero for an empty list.
Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.
CHECK YOUR UNDERSTANDING