Recursive Functions, Enumerability & Equivalent Computation Models
A deep account of primitive and partial recursive functions, unbounded search, computably enumerable sets, universal computation, and why Turing machines, lambda calculus, and other effective models compute the same class of functions.
Recursive-function theory describes computation without tapes, states, or source code. A program is built from a few numerical functions and closure operations; nontermination appears as an undefined value of a partial function. This austere model exposes three central facts: finite algorithms can be encoded by natural numbers, one universal evaluator can run any encoded algorithm, and some mechanically recognizable sets still have no total decision procedure.
Throughout, a partial -ary function is written
means the computation terminates with a value; means it diverges. Totality is a semantic property of the function, not a promise automatically supplied by its definition.
Primitive recursion: total computation by bounded construction #
The primitive recursive functions are the smallest class containing:
- Zero: .
- Successor: .
- Projections: .
- Composition: substitute already-built functions into another.
- Primitive recursion: from total and , define
The recursion parameter decreases from to , so evaluation always terminates. Every primitive recursive function is total.
Addition illustrates why the schema is computational rather than circular:
Multiplication is primitive recursion over addition; exponentiation is primitive recursion over multiplication. Booleans, comparisons, bounded sums and products, finite sequences, and bounded searches can all be encoded the same way.
Primitive recursive does not mean "easy" or "small." It is a structural class, not a complexity class. Its functions can grow extraordinarily fast. Yet it still omits total computable functions such as the Ackermann function; diagonalizing over all primitive-recursive definitions produces growth that escapes every fixed primitive-recursive construction.
Unbounded minimization introduces partiality #
The operator searches without a supplied bound:
and is undefined if no witness is ever found. Adding unbounded minimization to the primitive recursive functions yields the partial recursive (or -recursive) functions. A partial recursive function that happens to be total is called a general recursive function in the classical terminology.
For a minimal example, let
It returns for and searches forever for . A finite machine can implement exactly that behavior: test in order, halting at the first match.
The same operator captures semidecision. If is a decidable predicate meaning "step-coded history is a valid halting computation of program on input ," then
terminates exactly when program halts on . The undefined cases are not defects in the formalism; they are how it represents nontermination faithfully.
flowchart TD
B["Zero, successor, projections"] --> C["Composition"]
C --> PR["Primitive recursion"]
PR --> TOTAL["Primitive-recursive functions — always total"]
TOTAL --> MU["Add unbounded minimization μ"]
MU --> PARTIAL["Partial-recursive functions — may diverge"]
PARTIAL --> GEN["Restrict to functions that are total"]
GEN --> GENERAL["General-recursive functions"]
Coding finite objects as numbers #
Numerical models are not confined to intrinsically numerical tasks. Strings, trees, machine configurations, and finite computation histories can be effectively encoded as natural numbers. Pairing functions encode two numbers as one; repeated pairing encodes tuples and sequences. The encoding must support computable operations such as length, indexing, concatenation, and validation.
This yields an effective enumeration
of all partial recursive functions: is a program index and is the result of running program on . Different numbering schemes assign different indices, but acceptable schemes preserve universal interpretation and effective program manipulation.
Kleene's normal-form theorem sharpens the picture. There are primitive recursive predicates/functions and such that every partial recursive function can be written schematically as
checks whether is a valid completed computation record; extracts its output. All unbounded behavior is concentrated in the search for a completed history, while checking and decoding remain primitive recursive.
Decidable and computably enumerable sets #
For :
- is decidable (recursive) if its characteristic function is total computable: it returns for members and for nonmembers.
- is computably enumerable (c.e.; historically recursively enumerable) if some partial computable recognizer halts and accepts exactly the members of . On a nonmember it may reject or run forever.
- Equivalently, is c.e. if it is the domain of a partial recursive function, or the range of an effective enumerator (with minor conventions for the empty set).
| Input status | Decider | Recognizer for a c.e. set |
|---|---|---|
| Halts with yes | Eventually halts with yes | |
| Halts with no | May halt with no or diverge |
The bridge between recognition and enumeration uses dovetailing. To enumerate the set recognized by , do not run to completion before trying —the first run may never stop. At stage , execute one more step of each computation and emit inputs that have accepted. Every accepting run eventually gets its finite amount of time.
Two closure facts are diagnostic:
- c.e. sets are closed under union and intersection, but not under complement.
- is decidable iff both and its complement are c.e. Run the two recognizers in dovetailing fashion; exactly one must eventually accept.
The halting set: enumerable but undecidable #
Define
is c.e.: simulate program on and accept if it halts. Suppose a total decider for existed. Construct a program that loops when says "halts" and halts when it says "does not halt." Then:
- if says halts, loops;
- if it says does not halt, halts.
Both cases contradict correctness, so no such exists. The complement of is therefore not c.e.; otherwise and its complement would make decidable.
Equivalent models and the Church–Turing thesis #
Several models developed from different intuitions compute the same partial functions after effective encoding:
- Turing machines manipulate symbols by local state transitions.
- Partial recursive functions build number functions from equations and minimization.
- Untyped lambda calculus computes by substitution and -reduction.
- Register machines use finitely many unbounded counters.
- Post systems and normal Markov algorithms rewrite strings by finite rule sets.
Equivalence between any two formal models is a theorem: compile programs from one model into the other and prove that termination and output are preserved. The Church–Turing thesis is different. It identifies the informal notion of an effectively calculable procedure with Turing-computable/partial-recursive computation. Because one side is informal, the thesis is supported by convergence of models and robust experience, not proved as an ordinary equivalence theorem.
How to prove computability—or noncomputability #
For a positive result:
- Fix a precise encoding of inputs and outputs.
- Build the function from known recursive operations, or give a machine/program and prove equivalence.
- State whether it is partial or total.
- If total, provide a termination argument; syntax containing does not establish totality.
For a negative result:
- Assume a decider or total function for the target problem.
- Use it to decide a known undecidable set, usually through an effective mapping.
- Preserve both yes and no instances; a one-way implication is insufficient.
- Conclude that the assumed procedure cannot exist.
Diagonalization works because programs are both actors and finite data: once programs can be enumerated and interpreted, a constructed program can disagree with the alleged universal table on its own index. Gödel numbering, the universal evaluator, the halting set, and incompleteness are different manifestations of that same self-application boundary.