Lectures onType Theory
Chapter 123
Chapter 123Core route

Recursive Function Groups and Termination

The equations even(0)=tt,even(sucn)=odd(n),odd(0)=ff,odd(sucn)=even(n) compute by crossing from one definition to the other. Neither definition is a structural recursion in isolation. The group terminates because every crossing removes one successor. Replacing the last argument by sucn preserves typing and destroys that reason. A recursive-definition checker must therefore inspect a call graph, not just the type of each right side.

Groups and certified calls

Definition 123.1 — The Timpl-rec system card

Timpl-rec accepts a finite mutually recursive group G={fi:(Δi)Bi where Ci1iq}. Each Ci is an ordered Timpl-clauses matrix accepted by definition 121.1. Every strongly connected component chooses one of two decrease disciplines.

  1. A structural certificate names one explicit argument position of every function in the component. All named arguments inhabit either one mutual Timpl-data block at one common parameter vector or one primitive Timpl inductive type, N or Vec(c,) at one common element code c. At a recursive call the argument supplied in the callee’s named position must be a direct constructor child exposed by a clause split at the caller’s named position.

  2. A lexicographic certificate names a finite tuple of arguments and a well-founded relation for each coordinate. At a recursive call, the first coordinate that changes must strictly decrease; every earlier coordinate must be definitionally unchanged.

The target Timpl-rec-core is the literal union of the indexed Timpl fragment with the accessibility predicate, eliminator, and computation rule of definition 82.2, definition 82.6. No general fixpoint is added. Every accepted call is translated with its checked accessibility predecessor proof. Size-change matrices, sized types, semantic termination, effects, and higher-order recursive arguments are outside this card.

The target must contain both indexed families and accessibility. The accessibility fragment of definition 82.2, definition 82.6 alone would type the well-founded eliminator but has no vector family; bare Timpl has vectors but no accessibility eliminator. The named union states the exact delta.

Definition 123.2 — Function call graph

The function call graph has one vertex for each fi. An edge fifj records every syntactic call to fj in a reachable right side of fi, together with its clause path and candidate decrease certificate. Calls in shadowed rows are omitted because they cannot occur at run time. A strongly connected component is recursive exactly when it has more than one vertex or a self-loop.

The opening group yields one component with two vertices. All four clauses are reachable. Its two recursive edges carry the direct-child certificate nsucn.

Definition 123.3 — Structural descent judgment

At a clause leaf with branch context Θ, let x be the designated argument before splitting. The compiler records the finite set Child(x)Θ of recursive fields introduced by the single constructor split whose scrutinee is x. A later split of one of those fields does not add its descendants to Child(x). The judgment Θ;xudescx holds exactly when u is definitionally one of those recorded fields. It is not closed under arbitrary evaluation, transitivity, projections not introduced by the split, or user propositions about size.

Thus the call odd(n) in the successor clause passes. The calls odd(sucn) and odd(n+0) fail: the first is not a child, and the second is only propositionally equal to a child unless the selected Timpl conversion actually reduces it to n.

Definition 123.4 — Lexicographic call certificate

Fix well-founded relations Rh on Ah, for 1hd. A call from tuple a to b has a lexicographic certificate when there is a least coordinate k such that a1b1,,ak1bk1,bkRkak. Later coordinates are unrestricted. The certificate stores k, the conversion derivations for the prefix, and the proof of the strict step.

The least-coordinate requirement prevents a later decrease from masking an earlier increase. For pairs of naturals, (m,sucn) is below (sucm,0) only if the first coordinate decreases; the change in the second coordinate cannot repair a failed first comparison.

Definition 123.5 — Recursive-group rejection diagnostic

The Timpl-rec checker either returns a certified component list or one record RecReject(S,fifj,ω,δ,a,b,F). Here S is the computed component; fifj and ω name the source, target, and exact clause-tree call site; δ is the chosen structural or lexicographic discipline; a and b are the typed caller and callee tuples after the leaf substitution; and F is the failed certificate premise. In the structural case, F prints the named positions, the exposed direct-child set, and the failed definitional comparison. In the lexicographic case, it prints every earlier comparison through the first unequal coordinate and identifies either the earlier increase, the missing strict proof, or the exhausted equal tuple.

The checker computes components in source-vertex order, scans their reachable clause trees and call sites left to right, and compares lexicographic coordinates from first to last. Edges leaving S are recorded but require no predecessor certificate. The first internal edge without a complete certificate is returned; no diagnostic is selected by a fixture name.

Lemma 123.6 — Recursive rejection records a failed predecessor premise

If Timpl-rec returns RecReject(S,fifj,ω,δ,a,b,F), then the call at ω has no predecessor proof under the selected discipline using the checked comparisons stored in F.

Proof of Lemma 123.6 — Recursive rejection records a failed predecessor premise

Proof. For a structural discipline, inversion of definition 123.3 says that a predecessor proof must select a member of the finite direct-child set and convert the callee’s named argument to it. The diagnostic has enumerated that set and its stored comparison fails for every member. For a lexicographic discipline, inversion of definition 123.4 requires a least coordinate with an unchanged prefix and a supplied strict step. The left-to-right record either exhibits an earlier unequal coordinate without its strict step or exhausts the tuple without one. In either case the required constructor of the certified call relation cannot be formed. These are the two accepted disciplines. ◻

For one recursive component S, the compiler first generates the nonrecursive datatype StateS:U,ini:(a:Δi)StateS(fiS), at the maximum level of its constructor telescopes. This is an ordinary one-family Timpl-data block: no constructor argument mentions StateS, so the occurrence checker of definition 122.4 accepts it. The generated declaration and its eliminator are program data, not a new Timpl-rec-core rule. Its result family has branch BS(ini(a)):=Bi[a/Δi]. The relation over which the component recurses is the following one; every later statement of this chapter is about it.

Definition 123.7 — Mutual-block carrier and direct-child relation

Fix the common parameter vector p of a mutual datatype block B=(D1,,Dr) named by a structural certificate. The number r of block families is independent of the number q of functions. The certificate therefore stores, for every fi, a family tag κ(i):Finind(r) for its named argument. Here Finind is the indexed family, constructors, and eliminator fixed in chapter 31; the extensional finite-set presentation is not being used.

To make the varying index telescopes well formed, set LB:=max(0,maxllev(Δl),maxll) and define the tagged block payload by dependent elimination on l:Finind(r): PayloadB(l):=ı:ΔlDlpı:ULB. Each of the finitely many eliminator branches is the displayed iterated dependent sum. When a branch inhabits a smaller universe, the processor inserts the strict lift of definition 29.10; its decoding equation makes the lifted branch judgmentally equal to the displayed payload. Put CarrierB(p):=l:Finind(r)PayloadB(l):ULB. Its uniform direct-child relation DChildB is generated once on this total space. More precisely, let KB:=max(lev(Δp),LB,maxslev(Θs)). The processor submits the nonrecursive Timpl-data family DChildB:CarrierB(p)CarrierB(p)UKB with the constructors below. The maximum emitted by definition 122.13 is exactly KB: it includes the parameter telescope, both carrier-index binders, every constructor telescope, and the displayed family level. No constructor argument mentions DChildB, so definition 122.4 accepts the generated block. For every constructor c:ΘDlpı and every field xr:Dkpȷ of Θ whose head is a family of B, it has the constructor childc,r:DChildB((k,(ȷ,xr)),(l,(ı,cx))). The relation is defined on all tagged block inhabitants; it does not mention a clause leaf. Mutual induction on B constructs accessibility of every (l,(ı,a)), because each predecessor proof selects one recursive constructor field and the induction hypothesis supplies its accessibility proof.

For the two primitive choices the same notation has a separate, exact instance. On N, its only generator is childsuc:DChildN(n,sucn). At fixed c:U, the vector carrier is n:NVec(c,n), and its only generator is childvcons:DChildVec(c,)((n,xs),(sucn,vcons(n,a,xs))). The Nat-elim and Vec-elim rules construct the respective accessibility proofs. Thus the opening even–odd group uses DChildN; it does not pretend that N was declared by a Timpl-data block.

Lemma 123.8 — Inverse images preserve well-foundedness

Let μ:AB, let R be a well-founded relation on B, and define aμa by μ(a)Rμ(a). Then μ is well founded on A.

Proof of Lemma 123.8 — Inverse images preserve well-foundedness

Proof. Fix a:A. Eliminate the supplied proof AccR(μ(a)). Its step premise assigns AccR(b) to every bRμ(a). Given aμa, instantiate that premise at b=μ(a) and apply the accessibility induction hypothesis to obtain Accμ(a). The accessibility constructor therefore gives Accμ(a). Since a was arbitrary, the inverse-image relation is well founded. ◻

Lemma 123.9 — Finite lexicographic products are well founded

For n1, if each Rh is well founded on Ah, then the right-associated relation lex(R1):=R1,lex(R1,,Rn):=Lex(R1,lex(R2,,Rn))(n2) is well founded on A1××An, with products associated to the right in the same way as the relation.

Proof of Lemma 123.9 — Finite lexicographic products are well founded

Proof. Induct on n. The case n=1 is the supplied well-foundedness proof for R1. For n=m+1, the induction hypothesis makes lex(R2,,Rm+1) well founded on A2××Am+1. Apply theorem 82.16 to R1 and this relation. Its carrier is A1×(A2××Am+1), which is the stipulated right-associated product. ◻

Definition 123.10 — The certified tagged call relation

Let S choose the structural discipline and let pi be the position named by its certificate for fi. The carrier and the measure map out of each state constructor depend on the single discipline chosen by the component: disciplineXSμiS:ΔiXSBCarrierB(p)μiB(a)=ικ(i)(api)NNμiN(a)=apiVec(c,)n:NVec(c,n)μiVec(a)=(ni(a),api). Here κ(i) is present only in the mutual-block row, while ni(a) is the index at which the named vector argument is typed. In the mutual row, ιl(a) abbreviates (l,(ıi(a),a)) when a:Dlpıi(a). Write DChildS respectively for DChildB, DChildN, or DChildVec(c,). Put inj(b)RSini(a):=DChildS(μjS(b),μiS(a)). Thus neither κ nor a mutual-block carrier is silently assigned to a primitive discipline. Let S instead choose the lexicographic discipline with coordinates 1hd, relations Rh, and coordinate projections π. Put inj(b)RSini(a):=π(inj(b))lex(R1,,Rd)π(ini(a)), the finite lexicographic product of lemma 123.9. In both cases the tag is not part of the measure: it selects which projection is read, and a call may cross to any fj of the component. By construction each accepted recursive edge of definition 123.2 is one RS step, and its certificate is a proof of that step.

Lemma 123.11 — A stored structural certificate gives its discipline's child step

Suppose a clause split exposes constructor c at the caller’s named position and records uChild(x). After applying the leaf substitution, the stored certificate determines DChildS(μjS(b),μiS(a)), where a is the caller tuple and b is the callee tuple after that substitution.

Proof of Lemma 123.11 — A stored structural certificate gives its discipline's child step

Proof. By definition 123.3, u is definitionally one of the recursive fields introduced by that constructor split. There are three discipline cases. For a mutual block, let r be the field position and Dκ(j) its family. The generator childc,r relates ικ(j)(u) to ικ(i)(cx); the stored conversion identifies these terms with μjB(b) and μiB(a). For N, the only constructor that can expose a recursive field is suc, and childsuc relates the stored predecessor to the successor scrutinee. For Vec(c,), the only such constructor is vcons; childvcons relates the tagged tail (n,xs) to the tagged scrutinee (sucn,vcons(n,a,xs)). The callee typing conversion identifies its vector index with n. In every case the stored definitional equality identifies the callee’s named argument with the exposed field u, giving the displayed instance and no other child step. ◻

Lemma 123.12 — The accepted call relation is well founded

The relation RS of definition 123.10 is well founded on StateS under either discipline, and every accepted recursive edge of the component is one RS step.

Proof of Lemma 123.12 — The accepted call relation is well founded

Proof. In the mutual-block structural case, mutual induction on the accepted block constructs accessibility for DChildB on CarrierB(p). Pull it back along the map whose restriction to ini is μiB, using lemma 123.8. In the N case, Nat-elim constructs accessibility for DChildN; pull it back along the map with restrictions μiN. In the vector case, Vec-elim constructs accessibility for DChildVec(c,) on n:NVec(c,n); pull it back along the map with restrictions μiVec. These codomains differ, but a component chooses exactly one of them, so each use of the inverse-image lemma is typed. By lemma 123.11, every accepted syntactic Child certificate constructs exactly the predecessor proof for the chosen discipline. The function tag may change because the applicable measure map is selected by the state constructor.

In the lexicographic case, each edge contains the data required by definition 123.4: a least changed coordinate k, conversion derivations ahbh for h<k, and a proof of bkRkak. That is exactly one step of lex(R1,,Rd), which lemma 123.9 shows well founded from the declared Rh. Pull it back along π by lemma 123.8. Hence RS is well founded and each certificate is a predecessor proof. ◻

Exercise 123.1

★☆☆ For the lexicographic order lex(<,<) on N×N, classify calls from (sucm,n) to (m,suc(sucn)), (sucm,0), and (suc(sucm),0). In the second call, distinguish n=0 from n=suck. Give the decisive coordinate or the failed premise.

Compilation through accessibility

By lemma 123.12, every tagged input of the component has an accessibility proof for RS.

Definition 123.13 — Body translation

The translation of a case-tree leaf replaces a recursive call fjb made while defining fia by the recursive hypothesis supplied at the stored proof inj(b)RSini(a). Nonrecursive calls and constructors are translated homomorphically. Constructor splits remain the Timpl eliminators generated by the clause compiler.

For even and odd, constructor ineven denotes even and constructor inodd denotes odd. The translated body at ineven(sucn) invokes the recursive hypothesis at inodd(n); the odd body makes the opposite crossing. Eliminating the well-founded recursive function at the two state constructors reproduces the four opening equations.

Lemma 123.14 — Body translation is typed

Assume the clause compiler accepts every Ci, and every recursive edge in the component carries a certificate accepted by Timpl-rec. In the well-founded-recursion step context for ini(a), translation of the body of fi has type Bi[a/Δi].

Proof of Lemma 123.14 — Body translation is typed

Proof. Induct on the accepted case tree. A leaf without a recursive call uses clause compiler typing. At a recursive call, the stored structural or lexicographic certificate is a proof of inj(b)RSini(a); applying the recursive hypothesis to that proof yields the callee result type. Constructor-split nodes use the indexed eliminator and the induction hypotheses for their branches. A conversion node applies the Timpl conversion derivation already stored by the clause compiler. These are all node families. ◻

Two evaluation relations are needed to state what compilation preserves. A phrase such as “the two evaluations agree” would not identify either one.

Definition 123.15 — Closed source and recursive-core evaluation

For an accepted group G, let ΣG contain its accepted ambient Timpl signature, every Timpl-data block scrutinized by a clause tree, and every generated state block. A program root contraction is either a root contraction of definition 111.22 or a generated Block-comp equation belonging to one of those accepted blocks. The signature parameter matters because a split over a user declaration computes by its generated equation rather than by a fixed-kernel rule.

Let select(Ci,a)=(σ,e) mean that the ordered clause tree for fi, on the closed constructor tuple a, selects the reachable leaf e with branch substitution σ. The source root family also has select(Ci,a)=(σ,e)fia0RCalle[σ]RCall. Let C(G) be the Timpl-rec-core definition produced by definition 123.13, and write compileG(t) for its homomorphic extension to source term contexts. The target root family replaces R-Call by the macro-contraction select(Ci,a)=(σ,e)compileG(fia)0CCallcompileG(e[σ])CCall. The macro is licensed only when its left side contracts to its right side by the nonempty deterministic Timpl-rec-core sequence consisting of the generated outer definition beta contractions, the generated state-block equation, WF-β, and the administrative beta contractions introduced by body translation. It is a trace boundary, not a new target equality rule. The compiler marks that whole expansion as one administrative region. A fixed-kernel contraction strictly inside such a region is not an independent target program root; it is scheduled only as part of C-Call. Fixed-kernel contractions in homomorphic source positions and all shared Block-comp roots remain independent program roots.

For either grammar, a dynamic compatible context is a compatible term context of definition 111.22 except that it has no hole in an accessibility proof, a stored predecessor certificate, or a conversion witness introduced by the compiler. These positions remain available to kernel conversion and typing, but the program evaluator does not schedule them. Ordinary proof terms written by the programmer are not frozen. Write for closure of the appropriate root family under dynamic compatible contexts. The source and target grammars determine whether the third root family is R-Call or C-Call.

For closed terms, tRv means that a finite -sequence using the source root family carries t to the closed constructor normal form v. For closed target terms, tRCv means the analogous finite sequence using the target root family. Thus one source R-Call and one target C-Call have the same visible granularity, while every C-Call has the stated nonempty raw-core expansion. Neither relation borrows the execution calculus introduced in a later chapter.

Lemma 123.16 — Generated equations

Suppose select(Ci,a)=(σ,e). The source definition has the R-Call contraction fia0RCalle[σ]. Its compiled target has the C-Call contraction to compileG(e[σ]), and this contraction expands to a nonempty deterministic Timpl-rec-core sequence. Every recursive call in the target body uses the recursive hypothesis at its stored RS-predecessor proof.

Proof of Lemma 123.16 — Generated equations

Proof. The source contraction is the defining instance of definition 123.15. For the target expansion, the outer definition applications first install a, after which the generated state eliminator selects constructor ini. The accessibility proof begins with acc, so WF-β exposes the step term. The finitely many outer applications introduced by translation then beta-contract. By definition 123.13, the selected branch is compileG(e[σ]), and each recursive leaf receives exactly the hypothesis indexed by its stored predecessor certificate. The state tag and ordered clause selection make every contraction in this administrative prefix deterministic. This is precisely the side condition that licenses C-Call. ◻

Lemma 123.17 — One-step operational correspondence

Let t be a closed term reachable from a clause body of an accepted group G.

  1. If t takes one source step to t, then compileG(t) takes one target program step to compileG(t).

  2. If compileG(t) takes one target step, its reduct is compileG(t) for a unique source reduct t of t.

Proof of Lemma 123.17 — One-step operational correspondence

Proof. First inspect a root step. A fixed-kernel contraction is preserved literally because translation is homomorphic on that redex. A generated Block-comp step is also preserved literally: both sides use the same declaration from ΣG, constructor, and generated branch equation. A source R-Call and its target C-Call are the two contractions of lemma 123.16. Conversely, a root contraction of a translated reachable term belongs to exactly one of these three rule families. The first two reflect the identical source contraction. In the third, the state-constructor tag determines i, and ordered clause selection determines the unique R-Call reduct.

For a non-root step, induct on the dynamic compatible context. Rebuild the same context around the root argument in the forward direction. In the reverse direction, homomorphic translation identifies the unique source subterm at the hole; apply the induction hypothesis there and rebuild the context. A binder context first renames its bound variable fresh, while a conversion context retains its stored conversion derivation. There is no target-only hole inside compiler evidence by definition of a dynamic context. These are all dynamic compatible-context forms of definition 111.22 and the generated block rules. ◻

Lemma 123.18 — Finite operational correspondence

For every closed reachable t and closed constructor normal form v, tRvcompileG(t)RCv.

Proof of Lemma 123.18 — Finite operational correspondence

Proof. For the forward implication, induct on the source sequence and append the target program step from item 1 of lemma 123.17. Translation fixes constructor normal forms. For the reverse implication, repeatedly apply item 2 to the first target step. Each application consumes exactly that target program step; the finite target derivation therefore yields a finite source derivation. At its end, translation fixes v. If the target derivation has length zero, its source is already a constructor normal form because translation changes only recursive-call heads and neither creates nor removes such a normal form. ◻

Exercise 123.2

★☆☆ For the opening group, write the R-Call contraction at even(sucn) and the corresponding C-Call contraction. Expand the latter through its generated state-block and WF-β steps at ineven(sucn). Name the DChildN proof supplied to the recursive hypothesis.

Theorem 123.19 — Termination and elaboration of accepted groups

If Timpl-rec accepts G, then its checker terminates and returns a well-typed Timpl-rec-core definition for every fi. Evaluation of a compiled function at closed constructor data takes only finitely many recursive unfoldings. For every closed constructor input a and closed constructor value v, fiaRvC(G)iaRCv.

Proof of Theorem 123.19 — Termination and elaboration of accepted groups

Proof. The checker traverses finite clause trees and call sites. Structural checking compares a call argument with a finite child set; lexicographic checking scans a finite tuple and invokes the already terminating Timpl conversion checker. Thus checker execution terminates.

For each recursive component, lemma 123.12 gives the accessibility proof and lemma 123.14 gives the step of the well-founded recursor. Eliminating its result at each generated state constructor gives the typed target definitions. Accessibility induction shows that evaluation can unfold only at predecessor inputs, so a closed run has finitely many recursive unfoldings.

For the equivalence, apply lemma 123.18 to the closed term fia. Its translation is C(G)ia, and translation fixes v. The one-step lemma treats fixed-kernel, generated Block-comp, recursive, binder, and conversion contexts separately, so the finite-closure argument does not assume an unprinted congruence case. ◻

Corollary 123.20 — Functional induction for an accepted group

Let Timpl-rec accept a component S. For every fiS, fix a predicate Qi:(a:Δi)Bi[a/Δi]Uk. Suppose that, for each reachable clause leaf of fi at input a, the clause body establishes Qi(a,v) whenever every recursive call fjb in that leaf is supplied with Qj(b,vj) for its result fjbRvj. Then every closed constructor input a for which fiaRv satisfies Qi(a,v).

Proof of Corollary 123.20 — Functional induction for an accepted group

Proof. Apply accessibility induction to the tagged input ini(a) under the well-founded relation of lemma 123.12. Clause compilation selects one reachable leaf. Every recursive call in that leaf carries a stored predecessor proof, so the accessibility induction hypothesis supplies its required Qj premise. The assumed clause case then gives Qi(a,v). These cases cover every leaf of every function in the component. ◻

The call-order viewpoint and its predicative soundness proof are due to Abel and Altenkirch, Sections 2–5 [AA02]. Timpl-rec deliberately uses only direct structural children and explicit lexicographic witnesses; it does not import the more general foetus analysis.

Suggested first pass.

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

Exercise 123.3

★★☆ Construct the tagged input relation for even and odd. Give all four body translations. Calculate the compiled value of even(suc(suc0)), annotating both recursive unfoldings.

Exercise 123.4

★★☆ Change only the last opening equation to odd(sucn)=odd(sucn). Show the self-edge, the failed structural premise, and the infinite operational trace from odd(suc0).

Exercise 123.5

★★★ Practical project.recursive-group-descent-checker

Implement finite call graphs, strongly connected components, direct-child and two-coordinate lexicographic certificates in Kappa. Certify exactly the edges internal to a component, each by one verified predecessor proof. Bound reachability by the vertex count and justify that bound. Represent an edge by its source, target, call site, and coordinate comparisons; compute components from those edges rather than from fixture names. Accept even-odd, whose increasing auxiliary call leaves its component, and lex-reset. Reject same-argument and later-coordinate-only, computing the failing edge rather than printing a fixed verdict. Replay two oracle-failing mutations: ignore an earlier lexicographic increase, and drop the component filter. Each mutant must still typecheck, fail its exact stdout oracle, and retain an empty audit. The checker illustrates lemma 123.12; it proves no general termination theorem.

Search the book

Type to search the local edition.