ELIXIR / CHAPTER 09

Recursive list processing

Advanced

Write 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.

Elixir example
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]))
Result
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

Chapter checkpoint

Which step is tail recursive?