liveBook · Manning

Tail recursion

As explained in Elixir in Action, Third Edition

Tail recursion is recursion in which each recursive call is the final operation of the current function invocation.

Tail recursion is recursion in which the recursive call is the function's final operation. The compiler can implement that call as a jump rather than allocating another stack frame, so the function consumes no additional memory during iteration. section 3.4.2

This makes tail recursion suitable for loops that may run arbitrarily long. In Elixir, recursion supplies the loop, while function clauses handle the terminating and continuing cases. section 3.4.2 section 3.5

A practical tail-recursive design typically separates the public interface from the accumulator-driven recursion:

  • Expose a simple function such as sum/1. section 3.4.2
  • Delegate to a private helper carrying the accumulated result. section 3.4.2
  • Match the empty input and return the accumulator. section 3.4.2
  • Compute the next accumulator and make the recursive call last. section 3.4.2

Tail-recursive list sum

ListHelper.sum([1, 2, 3]) returns 6, while ListHelper.sum([]) returns 0. The helper advances through the list with current_sum and tail, then returns the accumulated value when the list is empty. section 3.4.2

Listing 3.9 Tail-recursive sum of the first n natural numbers (sum_list_tc.ex)
defmodule ListHelper do
 def sum(list) do
   do_sum(0, list)
 end

 defp do_sum(current_sum, []) do
   current_sum
 end

 defp do_sum(current_sum, [head | tail]) do
   new_sum = head + current_sum
   do_sum(new_sum, tail)
 end
end

Inspect the complete Elixir implementation, including the public wrapper, accumulator, pattern-matching clauses, and terminating case. section 3.4.2

How Elixir in Action, Third Edition covers it

How deep it goes
Explains jump-like execution, accumulator-based implementation, termination, and why non-final calls are not tail recursive.
Examples
Demonstrates an endless loop and a tail-recursive ListHelper.sum/1 implementation over empty and nonempty lists.
What it assumes
Assumes familiarity with functions and lists while teaching recursive clauses and accumulator passing through a concrete sum.
What you can do after
Build it from scratch as an Elixir accumulator-based loop that handles arbitrarily large iterations.
How it connects
Connects tail recursion with recursion, pattern matching, function clauses, accumulators, and iteration.

Also explained in

Compare how 4 books explain tail recursion →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Elixir in Action, Third Edition. The section links point to the parts of the book it draws on.