Lectures onType Theory
Chapter 105
Chapter 105Optional

Partiality and General Recursion in Dependent Type Theory

Prerequisites. Direct starred prerequisites: none. No later core chapter depends on this route.

Suppose every type admitted fixA:(AA)A,fixA(f)f(fixA(f)). At A=, choose f=λx.x. Then fix(f):. An unrestricted proof-level fixpoint makes the empty type inhabited before any program is run. General recursion must therefore return a computation that may fail to produce an A, rather than an inhabitant of A itself.

Partial elements record time without promising a result

Definition 105.1 — Partial elements

For each type A, define the coinductive type Aν by return:AAν,step:AνAν. Write a for returna and x for stepx. Guarded corecursion defines the divergent computation never:=never:Aν. The inductive convergence judgment xa has rules

aa
Conv-Return
xa
xa
Conv-Step

A partial element diverges, written x, when a:A.¬(xa). A finite observation observek(x) removes at most k leading steps and returns either later or done(a). It never asserts divergence from a finite prefix.

The type Aν is not A+1. Case analysis on A+1 decides whether a value is present. Constructively, an arbitrary partial element need not satisfy (a.xa)  x. Every finite observation of never returns later, but no finite observation proves that all later observations do so.

Definition 105.2 — Weak equality

Two partial elements are equal, written x=νy, when they have the same convergence behavior: x=νy:=a:A.xaya. This relation identifies x, x, and every finite delay of x. It is weaker than syntactic equality and strong bisimilarity.

Lemma 105.3 — Delay laws

For all x,y:Aν and a:A: x=νx,a=νxxa,x=νyx=νy. Moreover, =ν is an equivalence relation.

Proof of Lemma 105.3 — Delay laws

Proof. First prove determinacy of convergence: if xa and xb, induction on the first derivation and inversion of the second give a=b. The return case inverts both derivations; the step case removes one Conv-Step from each and applies the induction hypothesis.

For the first formula, inversion of Conv-Step gives xaxa, and Conv-Step gives the converse. For the second, inversion of Conv-Return shows that ab exactly when a=b. If xa, determinacy gives xba=b; substitute both facts in definition 105.2. The reverse implication specializes equality at a and uses Conv-Return. The third formula applies the first inversion in both directions. Reflexivity, symmetry, and transitivity hold pointwise because logical equivalence has those three properties. ◻

Exercise 105.1

★☆☆ Compute observek for 37 at k=0,2,3,4. Give the Conv-Step/Conv-Return derivation witnessing convergence and state why none of the first three observations is a proof of divergence.

Sequencing partial computations

Definition 105.4 — Partial bind

For f:ABν, define its extension f:AνBν by guarded corecursion: f(a):=f(a),f(x):=(f(x)). Write x=f for f(x).

The input step is retained. A tempting definition f(x)=f(x) is unguarded: computing its first constructor may require inspecting infinitely many input steps. Guarding the recursive call is forced by productivity.

Lemma 105.5 — Bind convergence

For x:Aν, f:ABν, and b:B, (x=f)ba:A.xaf(a)b.

Proof of Lemma 105.5 — Bind convergence

Proof. For the forward implication, induct on the convergence derivation. If x=a, choose a; Conv-Return proves the first conjunct and the premise proves the second. If x=x, inversion of the bind equation changes the final Conv-Step premise to (x=f)b. The induction hypothesis supplies a, and Conv-Step gives xa.

For the reverse implication, induct on the derivation of xa. The return case reduces bind to f(a). In the step case, the induction hypothesis gives (x=f)b; one use of Conv-Step and the second bind equation gives (x=f)b. ◻

Definition 105.6 — Lifted setoids and Kleisli arrows

A setoid A=(|A|,EqA) consists of a type |A| and an equivalence relation EqA on it. A map h:AB is a function |h|:|A||B| satisfying EqA(a,a)EqB(|h|(a),|h|(a)). Two such maps are equal when their values are EqB-related at every argument.

Lift A to a setoid TA as follows. For x:|A|ν and a:|A|, put ConvA(x,a):=a:|A|.xaEqA(a,a),EqTA(x,y):=a:|A|.ConvA(x,a)ConvA(y,a). For the discrete setoid, whose relation is ordinary equality, EqTA(x,y) is exactly x=νy.

Define ηA:ATA by ηA(a)=a. A Kleisli arrow f:ATB is a function |A||B|ν satisfying EqA(a,a)EqTB(f(a),f(a)). Its extension is the guarded function of definition 105.4: f(x):=x=f.

Lemma 105.7 — Extensional return and bind

Let A,B be setoids.

  1. TA is a setoid and ηA:ATA is a setoid map.

  2. If f:ATB is a Kleisli arrow, then f:TATB is a setoid map and (K)ConvB(f(x),b)a:|A|.ConvA(x,a)ConvB(f(a),b).

  3. If f,g:ATB are Kleisli arrows, EqTA(x,y), and EqTB(f(a),g(a)) for every a:|A|, then EqTB(x=f,y=g).

Proof of Lemma 105.7 — Extensional return and bind

Proof. Reflexivity, symmetry, and transitivity of EqTA hold pointwise because logical equivalence has those properties. Moreover, (R)ConvA(a,c)EqA(a,c). If EqA(a,a), transitivity and symmetry of EqA make the right side of (R) equivalent with EqA(a,c). Thus ηA preserves the setoid relations, proving clause 1.

For the forward implication of (K), choose b0:|B| with f(x)b0,EqB(b0,b). By lemma 105.5, choose a0:|A| such that xa0 and f(a0)b0. Reflexivity gives ConvA(x,a0), while the second displayed relation gives ConvB(f(a0),b).

Conversely, choose a:|A| from the right side of (K), then choose a0:|A| such that xa0,EqA(a0,a). Because f is a Kleisli arrow, EqTB(f(a0),f(a)). Hence ConvB(f(a),b) gives ConvB(f(a0),b). Choose b0:|B| with f(a0)b0 and EqB(b0,b). Bind convergence gives f(x)b0, which proves the left side of (K).

If EqTA(x,y), formula (K) has equivalent right sides for x and y. Thus f preserves the lifted relation. If also f(a) and g(a) are related for every a, replace both the first conjunct by the equivalence between x and y and the second by the equivalence between f(a) and g(a) in (K). The resulting equivalence for every b:|B| is clause 3. ◻

Theorem 105.8 — Partiality Kleisli triple

On the category of setoids, the object assignment ATA, the setoid maps ηA:ATA, and extension of Kleisli arrows ff form a Kleisli triple. Thus the following are equalities of setoid maps: ηA=idTA,fηA=f,gf=(λa.g(f(a))). No choice principle is assumed.

Proof of Theorem 105.8 — Partiality Kleisli triple

Proof. All displayed maps are setoid maps by lemma 105.7. For the first law, formula (K) and (R) give, for every a:|A|, ConvA(ηA(x),a)(K)b:|A|.ConvA(x,b)EqA(b,a)equivalenceConvA(x,a). The reverse direction of the second step chooses b=a; the forward direction uses the witness for ConvA(x,b) and transitivity of EqA. Hence ηA and idTA are pointwise related.

The return equation in definition 105.4 gives f(ηA(a))=f(a), so reflexivity of EqTB proves the second law. For the third, fix x:|A|ν and c:|C|. Repeated use of (K) gives the annotated calculation ConvC(g(f(x)),c)(K)b.ConvB(f(x),b)ConvC(g(b),c)(K)a,b.ConvA(x,a)ConvB(f(a),b)ConvC(g(b),c)(K)a.ConvA(x,a)ConvC(g(f(a)),c)(K)ConvC((λa.g(f(a)))(x),c). This is pointwise EqTC, as required. ◻

The construction acts on setoids, not only on their carrier types. The extensionality lemma and the three calculations above supply the setoid action and all three Kleisli laws. Equality of maps is pointwise setoid equality, so the proof uses neither functional extensionality nor quotient choice.

Exercise 105.2

★★☆ Attempt to prove associativity by syntactic equality. Give an input with one leading step for which the two unfoldings expose different guarded syntax before quotienting. Then complete the convergence calculation proving =ν.

A partial recursive program

Fix a decidable predicate P:NatBool. Unbounded search from n is defined guardedly by searchP(n):={n,P(n)=true,searchP(n+1),P(n)=false. Each recursive call lies below , so it defines a partial element even when no witness exists.

Theorem 105.9 — Search adequacy

For every n,m:Nat, searchP(n)mnmP(m)=truek.nk<mP(k)=false.

Proof of Theorem 105.9 — Search adequacy

Proof. For the forward implication, induct on the convergence derivation while unfolding the defining equation at the starting index. If P(n) is true, the computation is n; inversion gives m=n, and the bounded universal has no instance. If P(n) is false, inversion of Conv-Step gives searchP(n+1)m. The induction hypothesis gives n+1m, P(m)=true, and falsity on [n+1,m); add P(n)=false.

For the reverse implication, induct on mn. At zero, m=n and P(n)=true, so Conv-Return applies. At a successor difference, the bounded premise gives P(n)=false. The induction hypothesis yields convergence from n+1, and Conv-Step yields convergence from n. ◻

This theorem is partial correctness plus an exact convergence criterion. A total-correctness theorem additionally needs mn.P(m)=true. Without that premise, P(k)=false for all k makes every finite observation return later.

The construction scales to partial recursive functions. A partial-recursive presentation of arity k is generated by zero, successor, projections, composition, primitive recursion, and minimization. Recursion on such a presentation f:NatkNat defines a term fν:NatkNatν: total base functions are followed by η, composition uses the strict tuple followed by Kleisli extension, primitive recursion first recurses on the returned natural number and then extends over its partial argument, and minimization tests successive values by a guarded search.

Theorem 105.10 — Representability of partial-recursive presentations

For every arity k:Nat, partial-recursive presentation f:NatkNat, input n:Natk, and output m:Nat, f(n)=mfν(n)m.

Proof of Theorem 105.10 — Representability of partial-recursive presentations

Proof. Induct on the partial-recursive presentation. The induction hypothesis for each immediate subpresentation is the displayed equivalence at every input and output.

For zero and successor, fν(n) is respectively η(0) and η(n+1). Inversion of Conv-Return proves both directions. For the i-th projection, the strict tuple forces all inputs; each input is already a returned natural number, so its only convergence is to ni.

Suppose f=hg1,,gj. Repeated use of the Kleisli convergence law (K) gives fν(n)ma1,,aj.i=1jgiν(n)aihν(a)m. Apply the induction hypotheses for the gi and h. The result is exactly the relational clause for composition.

For primitive recursion, write f(n,0)=g(n),f(n,r+1)=h(n,r,f(n,r)). The translation defines an auxiliary fν by recursion on the returned counter and defines fν by Kleisli-extending fν over that counter. A subsidiary induction on r proves fν(n,r)mf(n,r)=m. The zero case is the induction hypothesis for g. The successor case uses (K) once; its witness a is characterized by the subsidiary induction hypothesis, and the remaining convergence is characterized by the induction hypothesis for h. A final use of (K) accounts for a partial counter and yields the required equivalence.

For minimization, suppose f(n)=μr.g(n,r)=0. Define the guarded search leastgν(n,r) by first evaluating gν(n,r); a returned zero yields η(r), and a returned successor takes one -step before searching from r+1. The search lemma leastgν(n,r)mrmg(n,m)=0q.rq<ms.g(n,q)=s+1 is proved by the two inductions used for theorem 105.9: forward, invert the finite convergence derivation; backward, induct on mr. At every test, the induction hypothesis for g converts evaluation of gν into the graph equation for g. Taking r=0 gives the defining least-witness clause for minimization. These six constructor cases exhaust the presentation grammar and complete the outer induction. ◻

The theorem supplies representability of every partial recursive function, not a decision procedure for convergence.

Exercise 105.3

★★☆ Take P(k) to test whether k2=2 over natural numbers. Prove that no value satisfies the right side of theorem 105.9. Show that every finite observation returns later, without assuming a general law deciding convergence or divergence.

Fixed points and exact assumptions

For functions f,g:ABν, write fg when every convergence of f(a) is a convergence of g(a). An operator F:(ABν)(ABν) is finitary when, for every f:ABν, a:A, and b:B, a derivation F(f)(a)b supplies a finite list (a1,b1),,(an,bn) such that f(ai)bi for every i, and every g:ABν satisfying all g(ai)bi also satisfies F(g)(a)b.

The fixed point is built by racing the approximants against one another, and the race has to be written down: it is the only construction in the chapter that a reader could not guess, and the choice-freedom claim below depends on its exact shape.

Definition 105.11 — Racing two partial elements, and a sequence

Define xy, the first of x and y to converge, by guarded corecursion on both arguments: by:=b,(x)b:=b,(x)(y):=(xy). For a sequence h:NatBν, define an auxiliary race:(NatBν)NatBνBν by racehnb:=b,racehn(x):=(raceh(n+1)(xh(n))), and put race(h):=raceh0never.

Each recursive call sits under a , so both definitions are productive. At step n the accumulated element has been raced against h(0),,h(n1), so every member of the sequence is eventually entered; that is the exact sense of “fair”. Two consequences of the definition are used below: race(h)b implies h(n)b for some n, because a convergence derivation is finite and its length bounds the index reached; and if h is increasing for , the converse holds.

Theorem 105.12 — Finitary least fixed point

Every finitary operator F has a fixed point Y(F) up to extensional partial equality. Moreover, for every f:ABν, if F(f)f, then Y(F)f.

Proof of Theorem 105.12 — Finitary least fixed point

Proof. Let k0(a)=never and kn+1=F(kn), and define Y(F)(a):=race(λn.kn(a)). First, F is monotone: if fg and F(f)(a)b, finitarity supplies pairs (ai,bi) with f(ai)bi; each is then a convergence of g(ai), so its closure clause gives F(g)(a)b. Since k0k1 holds because never converges to nothing, induction gives knkn+1, so the sequence is increasing and definition 105.11 gives Y(F)(a)bn.kn(a)b.

If F(Y(F))(a)b, finitarity selects finitely many convergences of Y(F). Each appears at some approximant; their maximum index N places them all in kN. Therefore kN+1(a)=F(kN)(a)b, so Y(F)(a)b. Conversely, induction on n shows knF(Y(F)), using monotonicity and knY(F). Thus F(Y(F))=νY(F).

If F(f)f, induction gives knf for every n; the displayed convergence characterization yields Y(F)f. Finitarity supplies the finite maximum index, while monotonicity moves the approximation chain through F.

No countable choice is used, and the reason is now visible. Choice would be needed to turn the family of statements “kn(a) converges for some n” into a function selecting such an n. Nothing here does that: race is a guarded corecursive program that takes the whole sequence as one argument, and the index is not chosen but read off the length of a finite convergence derivation. ◻

Dropping finitarity invalidates the maximum-index step: an output could depend on infinitely many approximants at once. Extensional equality is also substantive; the parallel search need not have the same constructor timing as F(Y(F)).

Two programs, five techniques

Two programs are enough to separate the techniques, provided both are written out. Let gcdsub(m,n):={m,n=0,n,m=0,gcdsub(mn,n),0<nm,gcdsub(m,nm),0<m<n. It is total, but neither recursive call is on an immediate constructor subterm of either argument, so a structural checker rejects it. searchP of section 105.3 is genuinely partial. Take each program through the two definitional techniques in turn, and write down what is actually accepted.

Accessibility, for the total program.

Well-foundedness is expressed positively by the accessibility predicate Acc:(A:Set)(≺:AAProp).AProp,acc:(A:Set)()(a:A).((x:A).xaAccA()x)AccA()a, with wfA():=a:A.AccA()a. Its eliminator is the principle of well-founded recursion wfr:(P:Aτ)(a:A).AccA()a(x.AccA()x(y.yxPy)Px)Pa, computing by wfrPa(accah)e=ea(accah)(λy.λq.wfrPy(hyq)e). To accept gcdsub, instantiate A:=Nat×Nat, take (m,n)(m,n):=m+n<m+n, and supply two things: a proof allacc:wf(Nat×Nat)(), which follows from well-foundedness of < on Nat by transporting along m+n; and one obligation per recursive call, 0<nm(mn)+n<m+n,0<m<nm+(nm)<m+n, both of which reduce to 0<n and 0<m respectively. The result is a total function NatNatNat, and it is a genuine value: gcdsub(6,4) evaluates to 2 with no residual proof obligation.

The same definition is accepted in the measure form Program Fixpoint gcd(m,n:Nat){measure (m+n)}, which generates the same two obligations and discharges the accessibility proof internally. The boundary is worth recording: the measure form supplies the definition and nothing else. It provides no induction principle for reasoning about the function afterwards, because the elaborated term is not the one the user wrote; the explicit wfr form keeps Acc visible and so supports well-founded induction over the same relation.

Accessibility, for the partial program.

The same route fails, and it fails for a stated reason rather than by awkwardness. A well-founded relation for searchP would have to make n+1n whenever P(n)=false. If P is false everywhere, that relation has the infinite descending chain 012, so no inhabitant of AccNat()0 exists and the first argument of wfr cannot be supplied. Restricting the domain to inputs below a witness repairs this, but only by assuming mn.P(m)=true—the very statement the search was meant to decide.

Delay, for both programs.

The delay type accepts both without an obligation, because definition 105.1 makes every recursive call guarded. Define gcdν(m,n):={m,n=0,n,m=0,gcdν(mn,n),0<nm,gcdν(m,nm),0<m<n, of type NatNatNatν. Both definitions are accepted, and the difference is in what one can then observe. For the total program the observations converge and the measure argument above turns into a convergence proof: observe2(gcdν(6,4))=later,observe3(gcdν(6,4))=done(2), since the arguments pass through (6,4), (2,4), (2,2), and (0,2), whose sums 10>6>4>2 witness the measure, so gcdν(6,4)=32. For P(k) testing k2=2, by contrast, observek(searchP(0))=laterfor every k, and exercise 105.3 shows that no finite k improves on this. The delay type therefore accepts the partial program at the price that its result is a partial element: extracting Nat from Natν needs a convergence proof, which for gcdν is available and for searchP is exactly what does not exist.

Inductive domains, for both programs.

The third technique changes the domain instead of the codomain. Read the recursive equations of a function as the clauses of an inductive predicate that holds exactly where the call tree is finite. For gcdsub this is Dom:NatNatProp,d0:m.Domm0,d1:n.Dom0n,d2:mn.0<nmDom(mn)nDommn,d3:mn.0<m<nDomm(nm)Dommn, and the function is then defined by structural recursion on the extra proof argument, gcdd:mn.DommnNat, matching on d0 through d3. For the total program one then proves mn.Dommn—by the same measure m+n—and recovers the type NatNatNat; evaluation now proceeds by recursion on the domain argument, which costs time the accessibility definition does not. For searchP the same predicate is definable and the same function is definable on it, but n.Domn is not provable, so what one obtains is a partial function one can still compute with and reason about—on exactly the arguments where the predicate is inhabited.

Termination casts and general recursion.

The two remaining techniques do not produce a definition inside the total theory at all. A termination cast asserts the missing obligation rather than discharging it: it accepts gcdsub at the total type without the measure argument, and it accepts searchP at that type too, which is precisely why the assertion is a trusted input and not a proof. A language with general recursion runs both programs as written: gcdsub(6,4) prints 2 and searchP(0) loops. Sjöberg’s calculus makes this respectable by separating the fragment whose terms may appear in types from the fragment that may diverge; the price is that the second fragment’s results are not available as proofs.

Suggested first pass.

None of these problems is a prerequisite for a later chapter. Begin with exercise 105.4, then complete exercise 105.6.

Exercise 105.4

★★☆ Reconstruct lemma 105.5 with every inversion rule named. Use it to prove congruence: if x=νy and f(a)=νg(a) for every a, then x=f=νy=g.

Exercise 105.5

★★★ Define subtraction-based gcd as a delayed computation. Prove that the measure m+n decreases in every recursive branch and derive convergence. Then state the total value extracted from the convergence proof. Compare the accepted definition with one using an accessibility argument.

Exercise 105.6

★★★ Practical project.partiality-fuel-observer Implement in Kappa a finite observer for return, step, bind, subtraction gcd, and unbounded search represented by a step function. Maintain the invariant that one unit of fuel removes at most one step. On gcd-6-4-20, search-even-from-3-4, and search-never-12, print done 2, done 4, and later, respectively. A mutation that removes a step without consuming fuel must fail an exact step-count oracle. The observer witnesses finite convergence; printing later is not a proof of divergence.

Sources. Partial elements, convergence, extensional equality, representability, finitary fixed points, and the strong partiality monad follow Capretta [Cap05]. Definition 4.1 and Theorem 4.2 are on printed pp. 15–16, Theorems 6.19–6.20 on printed p. 22, and Definitions 8.1 and Theorem 8.2 on printed pp. 24–25; each proof package is shorter than ten pages and is incorporated above. The comparison of domain predicates, accessibility, and assistant-specific general recursion follows Bove, Krauss, and Sozeau [BKS16]. The nonterminating dependent-language comparison is bounded to Sjöberg’s separate calculus [Sjo15]; it supplies no theorem for the coinductive signature printed here.

Search the book

Type to search the local edition.