PolymathicAll ideas →
Computer Science & AI

Recursion

A function that calls itself — productive when the recursive case shrinks the input.

In 1936, three different mathematicians — Alonzo Church in Princeton, Alan Turing in Cambridge, Stephen Kleene working with Church — independently formalised what it means to compute. Church's lambda calculus, Turing's machines, the general recursive functions of Gödel, Herbrand, and Kleene — three formalisms that turned out, somewhat startlingly, to be exactly equivalent in expressive power. The result became known as the Church-Turing thesis: any function intuitively computable can be expressed in any of these systems. Of the three, the one closest to how working programmers actually think is recursion — the trick of defining a function in terms of itself. The factorial: n! = n × (n-1)!, with the base case 0! = 1. It feels strange the first time you see it work — the function calls itself, and somehow the result is finite, correct, and useful.

Recursion works when a problem can be decomposed into smaller instances of the same problem. The recipe is always the same: (1) base case — the smallest instance, where the answer is given directly; (2) recursive case — express the answer to the current instance in terms of the answer to a strictly smaller instance; (3) trust the recursion — assume the function works on smaller inputs and call it. The mathematics underneath is induction: a recursive definition is correct if the base case is correct and the recursive case correctly composes the smaller-input answer. Where recursion shines: tree and graph traversal, divide-and-conquer algorithms (Mergesort, Quicksort, FFT), parsing (recursive-descent parsers fall straight out of recursive grammars), functional programming idioms (map, filter, fold), and language design itself (Lisp, the second-oldest programming language, treats programs and data as recursively structured lists). Where recursion fails or needs care: deep recursion overflows the call stack (most languages limit stack depth to a few thousand frames; very deep recursions need tail-call optimization or explicit iteration); naive recursion can do exponential redundant work (Fibonacci computed naively does O(2^n) calls because F(n-1) and F(n-2) re-compute their subtrees; memoization or dynamic programming converts this to O(n)). Recursion's deeper significance: it is the simplest concrete demonstration that self-reference in computation is not paradoxical but constructive. The same trick that, applied carelessly, produces Russell's paradox in set theory and Gödel's incompleteness theorem produces, applied carefully, useful programs. The dividing line — between productive self-reference and paradoxical self-reference — is roughly whether the recursive case strictly reduces the problem.

Why it matters now

Recursion is a foundational primitive of contemporary CS, but it is not always the right idiom for production code. Iteration is often clearer and faster; modern compilers can usually convert tail-recursive code to iteration but can't help with non-tail recursion. Functional programming languages (Haskell, Lisp, Scheme, Clojure, Erlang, Elixir) lean heavily on recursion as the primary control-flow primitive. Tree-structured data — DOM trees, file systems, ASTs, JSON, decision trees, scene graphs in 3D rendering — are everywhere in modern software, and recursion is the natural way to walk them. Noam Chomsky's 1957 generative grammar, the foundational claim of modern linguistics, is that human language is recursive — sentences contain sentences, and the recursive structure is what makes the infinite expressive range of natural language possible from a finite grammar. In LLMs, transformer models do not use recursion in any deep architectural sense, but whether a system can reason recursively without an explicit recursion primitive is one of the open empirical questions in current AI research.

Read it in Polymathic →Browse the catalogue
Polymathic — a curated catalogue of the ideas worth keeping across twelve disciplines. polymathic.app