← back to programming

Recursion & Iteration

Abelson & Sussman · 1996 · SICP §1.2

A recursive procedure can generate an iterative process. The shape of the process — stack growth vs constant space — matters more than whether the procedure calls itself.

linear recursion (fact 4) (* 4 (fact 3)) (* 4 (* 3 (fact 2))) (* 4 (* 3 (* 2 (fact 1)))) (* 4 (* 3 (* 2 1))) (* 4 (* 3 2)) (* 4 6) 24 grows iterative process (fact-iter 1 1 4) (fact-iter 1 2 4) (fact-iter 2 3 4) (fact-iter 6 4 4) (fact-iter 24 5 4) 24 constant

Linear recursion — factorial

The naive factorial builds a chain of deferred multiplications. Each call adds a frame to the stack. Space grows linearly with n. This is a linear recursive process.

Scheme

Iterative process — factorial with accumulator

Same recursive procedure, different process shape. The accumulator carries the running product. Each call passes all state forward — no deferred operations, constant space. Scheme guarantees tail-call optimization, so this runs in O(1) space.

Scheme

Tree recursion — Fibonacci

Fibonacci via the naive definition branches at each step. The call tree has exponential nodes — the same subproblems are recomputed many times. It's beautiful and wasteful. The iterative version below runs in linear time and constant space.

Scheme

Orders of growth

The key question: how do time and space scale with input size? Linear recursive factorial: Θ(n) time, Θ(n) space. Iterative factorial: Θ(n) time, Θ(1) space. Tree Fibonacci: Θ(φn) time, Θ(n) space. The shape of the process determines the resource profile.

Scheme

Notation reference

Scheme Python Meaning
(define (f x) body)def f(x): bodyRecursive procedure
(define (iter a b) ...)for / while loopIterative process (tail call)
(even? n)n % 2 == 0Parity test
Θ(n), Θ(log n)O(n), O(log n)Orders of growth
(cond (p1 e1) (else e2))if p1: e1; else: e2Multi-branch conditional
Neighbors

Other reading pages

Foundations (Wikipedia)

Translation notes

Scheme guarantees tail-call optimization: a tail-recursive procedure runs in constant space. Python does not — deep recursion hits the stack limit. The Python translations use explicit loops where SICP uses tail recursion. The even? predicate becomes n % 2 == 0. SICP's Θ notation (tight bound) is more precise than big-O (upper bound), but they coincide for these examples.

Ready for the real thing? Read SICP §1.2.