liveBook · Manning

Tail recursion

As explained in Functional Programming in Scala, Second Edition

Tail recursion is recursion in which the recursive call is the final computation of the calling function, allowing constant-stack evaluation when supported by the language.

Tail recursion is recursion where the recursive call is the function’s final computation: its result returns directly, without further manipulation. This lets recursive loops run without growing the stack. section 2.7

The usual pattern moves unfinished work into parameters. An accumulator or carried-forward state records what earlier recursive calls would otherwise need to do after returning, so the next call can finish the computation directly. section 2.7 section 6.8

A tail-recursive loop typically follows these steps:

  • Define a local recursive helper with parameters for the remaining work and accumulated or current results. section 2.7
  • Stop at a base case and return the accumulated result. section 2.7 section 6.8
  • Otherwise, update the state and make the recursive call as the entire returned expression. section 2.7 section 2.7

Fibonacci with carried state

The helper tracks the remaining count, the current Fibonacci number, and the next one. Each call shifts next into current and computes a new next, avoiding deferred additions after recursion. section 2.7

def fib(n: Int): Int =
  @annotation.tailrec
  def go(n: Int, current: Int, next: Int): Int =
    if n <= 0 then current
    else go(n - 1, next, current + next)
 
  go(n, 0, 1)

Inspect a complete Scala implementation: the recursive call is the final expression, and @annotation.tailrec marks the intended optimization. section 2.7

def isSorted[A](as: Array[A], gt: (A,A) => Boolean): Boolean =
  @annotation.tailrec
  def loop(n: Int): Boolean =
    if n + 1 >= as.length then true
    else if gt(as(n), as(n + 1)) then false
    else loop(n + 1)
 
  loop(0)

Compare the same loop shape in isSorted, where the helper advances an array index and terminates at the final adjacent pair. section 2.7

How Functional Programming in Scala, Second Edition covers it

How deep it goes
Defines tail position and demonstrates accumulator-based loops, but does not develop compiler implementation details.
Examples
Uses Fibonacci calculation, adjacent-array comparison, and random-integer list generation as concrete tail-recursive traversals.
What you can do after
Build it from scratch as Scala recursive loops using local helpers, explicit state parameters, base cases, and @annotation.tailrec.
How it connects
Connects recursion with looping, accumulators, arrays, immutable lists, and higher-order functions.

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 Functional Programming in Scala, Second Edition. The section links point to the parts of the book it draws on.