Let 𝐴 :U𝑖, 𝑚,𝑛 :ℕ, 𝑎 :𝐴, 𝑥𝑠 :𝖵𝖾𝖼(𝐴,𝑚), and 𝑦𝑠 :𝖵𝖾𝖼(𝐴,𝑛). The two equations 𝖺𝗉𝗉𝖾𝗇𝖽(𝗏𝗇𝗂𝗅,𝑦𝑠)=𝑦𝑠,𝖺𝗉𝗉𝖾𝗇𝖽(𝗏𝖼𝗈𝗇𝗌(𝑚,𝑎,𝑥𝑠),𝑦𝑠)=𝗏𝖼𝗈𝗇𝗌(𝑛+𝑚,𝑎,𝖺𝗉𝗉𝖾𝗇𝖽(𝑥𝑠,𝑦𝑠)) state the desired computations, but they are not a term of dependent type theory. The second left side determines that the length of the first vector is 𝗌𝗎𝖼(𝑚); the right side then has type 𝖵𝖾𝖼(𝐴,𝗌𝗎𝖼(𝑛 +𝑚)), which is judgmentally the required type 𝖵𝖾𝖼(𝐴,𝑛 +𝗌𝗎𝖼(𝑚)). A compiler has to discover this refinement, reject impossible or uncovered branches, and construct the motive of the vector eliminator.
The hand translation in construction 78.7 performs these operations for append. It does not determine what to do with an arbitrary ordered matrix of clauses. The missing operation is a total compiler for one fixed clause language whose output realizes exactly the computations asserted by its reachable clauses.
The clause layer over the kernel
The compiler elaborates notation; it adds no rule to the kernel. Its source must therefore be fixed separately from the target theory.
The target Timpl is exactly the kernel frozen in convention 112.1; this chapter adds no target former or computation rule. The source restriction below permits splitting only the finite constructor families named by that card and permits recursion only through a displayed structural eliminator.
Timpl-clauses adds an untrusted, first-order clause layer with the following exact boundary.
A declaration has one Timpl argument telescope Δ=(𝑥1:𝐴1,…,𝑥𝑟:𝐴𝑟) and a result type 𝐵 in that telescope. The only inductive families that may be split are the finite constructor families declared in Timpl.
Patterns have the grammar 𝑝::=𝑥∣𝑐(𝑝1,…,𝑝𝑘)∣.𝑡∣! Pattern variables are linear, and constructor patterns are first order. The term 𝑡 in .𝑡 is a Timpl term in the full pattern-variable context of its row; it binds no variable. Pattern elaboration rejects a cyclic dependency among inaccessible terms.
Clause rows are ordered. At a compiler node, the first surviving row is the earliest row not deleted by an earlier constructor-branch filter. A blocking pattern in that row is an unresolved constructor or absurd pattern in a runtime column; variables and inaccessible terms do not block. The compiler scans the first surviving row from left to right and chooses the column of its first blocking pattern. An unresolved constructor or absurd pattern in an erased column instead produces a relevance error. When two rows overlap, the earlier row has priority.
Every binder retains its inherited runtime or erased annotation. Index constraints and inaccessible terms may mention erased variables, but the compiler never branches on their run-time values. A right side may use an erased pattern variable only where the Timpl relevance rules permit it.
Splitting 𝑥 :𝐷(⃗𝑢) with 𝑐 :(⃗𝑦 :Δ𝑐) →𝐷(⃗𝑣𝑐) generates the homogeneous index constraint (⃗𝑢;𝑥) ≡Ξ;𝐷(⃗𝑣𝑐;𝑐(⃗𝑦)), where Ξ is the index telescope of 𝐷. The compiler uses exactly the restricted unifier of definition 78.9. A positive result carries a dependency-preserving most general substitution, a negative result carries a conflict or cycle certificate, and a stuck result rejects the declaration. Such a substitution 𝜎 :Θ′ →Θ is dependency preserving when its solution and injectivity transitions are those of definition 78.9, up to the stable adjacent exchange of independent declarations needed to expose a solution. Every such exchange preserves the relative order of all declarations not exchanged, and every dependency of a declaration remains earlier than that declaration in Θ′.
When a row becomes the first surviving candidate, each inaccessible term in that row is checked, never inspected at run time. It is accepted only when the accumulated substitution makes the pattern position judgmentally equal to that term. The compiler rejects a merely plausible but unforced inaccessible term. An absurd pattern in that row is accepted only when every constructor gives a negative unification certificate. Assertions in a shadowed later row are discarded by ordered priority; they are neither validated nor accepted as equations or impossibility evidence.
A right side is a Timpl term at the result type instantiated by its written row map, in a context containing the declared identifier at its complete iterated function type. A nonrecursive declaration requires that identifier not to occur in a right side. A single structurally recursive definition may contain it only as a saturated call. Its designated argument must be a direct recursive child made available by the split, and the branch path must carry the corresponding child certificate. Mutual recursion, nested recursion, guards, views, higher-order patterns, nonlinear patterns, and unification outside the restricted constructor fragment are not in Timpl-clauses.
The intermediate target is an ordered case tree. The kernel target is the Timpl term obtained from that tree using the declared eliminators. The observable operation is evaluation of the target term at closed argument tuples satisfying the relevance-indexed readiness judgment of definition 121.5.
The layer adds no conversion rule, universe rule, identity principle, coinductive object, or erasure rule. In particular, its compiler may not delete a reflexive equality constraint and does not assume K.
Referenced from 8 locations
The delta has a sharp consequence. A covered clause declaration can now be accepted and translated, but two overlapping source rows no longer denote two unconditional equations. First-match selection determines which residual part of each row remains; generated equations are attached to those residual parts. This repairs the failure of reading an ordered clause list as an unordered equational theory.
Rows match in order
Dependency changes the types of the columns, but not the elementary reason that specialization preserves first-match order. We isolate that reason before putting telescopes on the matrix.
Fix finite constructor signatures, and let 𝑝::=_∣𝑐(𝑝1,…,𝑝𝑘) be nondependent patterns. A simple clause matrix 𝑃 ⇒⃗𝑎 is a finite ordered list of equal-width pattern rows, each carrying an action 𝑎𝑖. Matching a constructor-value tuple returns the action on its least matching row; _ matches every value.
With the selected column first, write 𝑆𝑐(𝑃 ⇒⃗𝑎) for constructor specialization. It processes rows in order:
replace a 𝑐-cell by its child patterns;
a cell headed by 𝑑 ≠𝑐 deletes the row; and
a wildcard is replaced by 𝑘 wildcards.
The other cells and the action are unchanged. The default matrix 𝐷(𝑃 ⇒⃗𝑎) retains, in order, just the rows whose selected cell is a wildcard and removes that cell. It is the branch action for a constructor whose head does not occur in the selected column. Selecting another column first means permuting that column to the front, applying these operations, and restoring the residual order.
Referenced from 3 locations
Let the first component of a constructor-value tuple be 𝑐(𝑤1,…,𝑤𝑘). The least row of 𝑃 ⇒⃗𝑎 matching that tuple has action 𝑎𝑖 if and only if the least row of 𝑆𝑐(𝑃 ⇒⃗𝑎) matching (𝑤1,…,𝑤𝑘,𝑣2,…,𝑣𝑛) has action 𝑎𝑖. If 𝑐 does not occur as a head in the selected column, the latter matrix may equivalently be replaced by 𝐷(𝑃 ⇒⃗𝑎) and the constructor children omitted. In both statements the residual row has the same original row number 𝑖.
Referenced from 6 locations
Proof of Lemma 121.4 — Matching decomposition preserves the least row
Proof. Inspect rows in their original order. A row headed by 𝑐 matches the first component exactly when its children match ⃗𝑤; a row headed by a different constructor matches neither side; and a wildcard row matches both sides. These are exactly the three clauses defining 𝑆𝑐, and none permutes retained rows. Hence the first successful row is the same. When 𝑐 is absent from the column heads, only wildcard rows survive, which is exactly 𝐷. ◻
For the two Boolean rows 𝗍𝗍_0__1 specialization at 𝗍𝗍 gives the one-column rows (_ ∣0),(_ ∣1), whose least action is 0. The set of written heads in the first column is {𝗍𝗍}, so the 𝖿𝖿 branch uses the default matrix (_ ∣1) and returns 1. Thus the wildcard action is copied into the true specialization but remains shadowed there; it becomes least only in the default branch.
This is the exact nondependent boundary taken from Maranget’s matrix decomposition: specialization, a default matrix, and preservation of ordered matching. His decision-tree heuristics may choose any useful column and analyze sharing, exhaustiveness, and redundancy in an ML pattern language. They establish no dependent substitution, index refinement, or Timpl typing claim. Timpl-clauses keeps only the decomposition lemma and fixes the first blocker of the first surviving row. Its dependent matrix state replaces the rectangular fringe by a typed frontier telescope.
Every Timpl binder has relevance 𝜚 ∈{𝗋𝗎𝗇𝗍𝗂𝗆𝖾,𝖾𝗋𝖺𝗌𝖾𝖽}. The typed readiness judgment for a supplied argument is generated by ⋅⊢𝑣:𝐴𝑣 is a closed runtime value⋅⊢𝑣𝗋𝖾𝖺𝖽𝗒𝗋𝗎𝗇𝗍𝗂𝗆𝖾:𝐴⋅⊢𝑛:𝐴𝑛 is in closed normal form⋅⊢𝑛𝗋𝖾𝖺𝖽𝗒𝖾𝗋𝖺𝗌𝖾𝖽:𝐴. Runtime values are lambdas, pairs of runtime values, and declared constructors whose runtime children are runtime values. The erased children stored under such a constructor need only be closed and well typed: they are not themselves tested by the readiness judgment, and no value grammar or evaluation-context position descends into them. By contrast, an erased argument supplied to a function binder satisfies the displayed erased rule and hence is a closed normal form before beta reduction. A tuple is ready when every component satisfies the rule indexed by its declared relevance. Only a runtime-relevant family component may be split, and then its weak-head form must be a declared constructor. Parameters such as 𝐴 :U𝑖 need not themselves have constructor form. For the vector constructor used below, the index argument of 𝗏𝖼𝗈𝗇𝗌 is erased, while its element and tail arguments are runtime.
Referenced from 9 locations
Fix a universe level 𝑗, a Timpl telescope Δ, and a result-type derivation Δ ⊢𝐵 :U𝑗. For Δ =(𝑥1 :𝐴1)𝜖1,𝜚1,…,(𝑥𝑘 :𝐴𝑘)𝜖𝑘,𝜚𝑘, define its iterated product by Π∅𝐵:=𝐵,Π(𝑥:𝐴)𝜖,𝜚,Δ𝐵:=∏𝜖,𝜚𝑥:𝐴ΠΔ𝐵. This notation retains every explicitness and relevance annotation. Put 𝐹Δ:=ΠΔ𝐵. For a substitution 𝜎 :Ω →Θ, its identity extension across the recursive identifier is 𝜎𝑓:(𝑓:𝐹Δ,Ω)→(𝑓:𝐹Δ,Θ),𝜎𝑓(𝑓):=𝑓,𝜎𝑓(𝑥):=𝜎(𝑥)(𝑥∈Θ).
A dependent pattern matrix is useful only after its binding and matching actions have been made exact. Let ⃗𝑣 :Δ be a closed well-typed ready tuple.
First define the binding judgment 𝖻𝗂𝗇𝖽𝗌(𝑝,𝑎,𝜃;O). It collects the bindings and the finite set O of inaccessible obligations made by a pattern at a closed ready argument. Such an argument may be an erased type, lambda, or index. Constructor form is required only when the pattern at that exact position is a constructor pattern. Write 𝜀𝗌𝗎𝖻 for the empty pattern-variable substitution.
𝖻𝗂𝗇𝖽𝗌(𝑥,𝑎,[𝑎/𝑥];∅) holds for any closed, well-typed argument 𝑎.
The judgment 𝖻𝗂𝗇𝖽𝗌(𝑐(𝑝1,…,𝑝𝑘),𝑐(𝑣1,…,𝑣𝑘),𝜃;O) holds if the component binding judgments hold, their substitutions have disjoint domains whose union is 𝜃, and their obligation sets have union O. Runtime children satisfy the runtime readiness rule; an erased constructor child is merely a closed well-typed payload and is not traversed by evaluation. Distinct constructor heads do not match.
𝖻𝗂𝗇𝖽𝗌(.𝑡,𝑎,𝜀𝗌𝗎𝖻;{(𝑎,𝑡)}) holds for any closed well-typed argument 𝑎; an inaccessible pattern contributes no binding and records the value at its exact nested position.
𝖻𝗂𝗇𝖽𝗌(!,𝑎,𝜃;O) never holds.
The relation 𝗆𝖺𝗍𝖼𝗁𝖾𝗌(⃗𝑝,⃗𝑎,𝜃) holds if the component binding substitutions have disjoint union 𝜃 and every recorded (𝑎,𝑡) ∈O satisfies 𝑎 ≡𝑡[𝜃]. Thus all pattern variables are collected before inaccessible terms are checked. Given ordered rows 𝑓 ⃗𝑝𝑖 =𝑒𝑖, the source root step at ⃗𝑎 selects the least 𝑖 for which 𝗆𝖺𝗍𝖼𝗁𝖾𝗌(⃗𝑝𝑖,⃗𝑎,𝜃) holds, where 𝜃 : ⋅ →Θ𝑖, and returns 𝑒𝑖[𝜃𝑓], leaving the explicitly typed recursive identifier 𝑓 :𝐹Δ unchanged. In the source dynamics, that remaining variable is interpreted by the declared head 𝑓. The tuple ⃗𝑎 is ready in the sense of definition 121.5. Consequently a runtime split-family position has constructor form when a constructor pattern inspects it, while an unrelated erased type or lambda in the same tuple need not have constructor form.
Referenced from 5 locations
The inaccessible clause is a compile-time assertion. A successful compiler proves its equality while specializing the matrix and erases the dot before run time. The source matching relation specifies the accepted equations; it is not an additional equality-deciding operation in the target.
Consider the ordered rows 𝖼𝗁𝗈𝗈𝗌𝖾(𝗍𝗍,𝑛)=𝟢,𝖼𝗁𝗈𝗈𝗌𝖾(𝑏,𝑛)=𝗌𝗎𝖼(𝟢). The first column is blocking, so the case tree splits it. Its 𝗍𝗍 branch uses the first row. Its 𝖿𝖿 branch uses the second row. Hence 𝖼𝗁𝗈𝗈𝗌𝖾(𝗍𝗍,𝑛)≡𝟢,𝖼𝗁𝗈𝗈𝗌𝖾(𝖿𝖿,𝑛)≡𝗌𝗎𝖼(𝟢). The unqualified assertion 𝖼𝗁𝗈𝗈𝗌𝖾(𝑏,𝑛) ≡𝗌𝗎𝖼(𝟢) is false at 𝑏 =𝗍𝗍 and is not a generated equation.
Referenced from 3 locations
★☆☆ Reverse the two rows of example 121.7. Construct the resulting case tree and list all of its judgmental equations. Explain why the constructor row is unreachable. (Five lines.)
Referenced from 3 locations
Let 𝑓 :𝐹Δ. A nonabsurd raw row consists of a pattern-variable context Θ𝑖, a written pattern tuple ⃗𝑝𝑖, and its written row map ̂𝜌𝑖 :Θ𝑖 →Δ. This map reads a variable as that variable, a constructor pattern as the corresponding constructor term, and an inaccessible cell .𝑡 as the term 𝑡 the programmer actually wrote. It does not assert that 𝑡 is forced. The row also carries a derivation in the explicit recursive-identifier context 𝑓:𝐹Δ,Θ𝑖⊢𝑒𝑖:𝐵[̂𝜌𝑖]. Every occurrence of 𝑓 in 𝑒𝑖 is therefore typed at 𝐹Δ. The source card further requires each such occurrence to be a saturated call whose designated argument is a certified direct child. Thus 𝑒𝑖[𝜎𝑓] specializes the pattern variables and preserves the recursive identifier with its type. Formation of ̂𝜌𝑖 checks each written dot term at its exact pattern position in Θ𝑖, after the stable reordering of independent declarations permitted by its acyclic dependency graph. It checks no forced-term equality. An absurd source row has the same well-scoped pattern data but no total written map at the absurd cell and no right side. It asserts that the cell has no reachable constructor. Every pattern variable occurs once.
During compilation, a surviving row carries its original number 𝑖, its residual patterns, a partial assignment of its pattern variables, and a finite ordered list O of typed residual obligations. New obligations are appended in left-to-right pattern order. An obligation is either an equality 𝑢 ≡𝑡 :𝐴, or a suspended forced match 𝑝𝖿𝗈𝗋𝖼𝖾𝖽𝖡𝗒𝑢 :𝐴. A selected dot creates an equality from the forced branch term 𝑢 and the written term 𝑡. A constructor pattern against a neutral forced image creates the second form instead of assuming that the pattern was accepted. Later matrix specialization substitutes through both forms. At a frontier map 𝜌 :Θ →Δ, the row-map invariant says that every well-typed match of all residual patterns by a substitution 𝜐 :Ω →Θ, with completed pattern-variable assignment 𝜏 :Ω →Θ𝑖, satisfies (O[𝜐] holds)⟹̂𝜌𝑖𝜏≡𝜌𝜐. Here O[𝜐] holds when every equality is judgmental and every forced match succeeds structurally at the instantiated constructor head. The initial row state has no residual obligations. The implication follows componentwise from the definition of matching: constructor cells recurse, variables supply the assignment, and written dots supply exactly the equality premise that was not assumed when the raw row was formed.
A clause matrix at a frontier Θ is a finite ordered list of such residual row states. Every state has one pattern for each declaration of Θ, in frontier order, followed by either its original right side checked under 𝑓 :𝐹Δ, or an absurd marker.
Referenced from 4 locations
Timpl-clauses uses a deliberately mixed checking time. Scope, linearity, the written row map, and the body typing derivation are checked for every source row before matrix compilation. Forced-dot equalities, suspended forced matches, and absurd assertions are checked only when their row becomes the least surviving candidate; a shadowed row needs only the former scope and body checks. One general dependent-clause compiler permits the right side itself to be checked after splitting, whereas Agda 2.5.4 retains a separate pass that checks each clause individually before building the combined case tree. The Timpl-clauses policy is neither one: bodies are checked early against written maps, but reachability-sensitive dot and absurd obligations are checked late. In particular, it does not claim to describe the interaction-hole behavior of Agda.
For append, the elaborated rows carry more information than the two equations at the chapter opening. Extend the iterated-product notation by the following exact recursive abstractions and applications: 𝜆∅𝑒:=𝑒,𝜆(𝑥:𝐴)𝜖,𝜚,Δ𝑒:=𝜆𝜖,𝜚(𝑥:𝐴).𝜆Δ𝑒,𝑓@∅():=𝑓,𝑓@(𝑥:𝐴)𝜖,𝜚,Δ(𝑎,⃗𝑏):=(𝑓𝜖,𝜚𝑎)@Δ(⃗𝑏). Thus no metadata is hidden. Put Δ𝖺𝗉𝗉:=(𝐴:U𝑖)𝗂𝗆𝗉,𝖾𝗋𝖺𝗌𝖾𝖽,(𝑚:ℕ)𝗂𝗆𝗉,𝖾𝗋𝖺𝗌𝖾𝖽,(𝑛:ℕ)𝗂𝗆𝗉,𝖾𝗋𝖺𝗌𝖾𝖽,(𝑥𝑠:𝖵𝖾𝖼(𝐴,𝑚))𝖾𝗑𝗉,𝗋𝗎𝗇𝗍𝗂𝗆𝖾,(𝑦𝑠:𝖵𝖾𝖼(𝐴,𝑛))𝖾𝗑𝗉,𝗋𝗎𝗇𝗍𝗂𝗆𝖾. The complete elaborated type is 𝐹𝖺𝗉𝗉:=ΠΔ𝖺𝗉𝗉𝖵𝖾𝖼(𝐴,𝑛+𝑚),𝖺𝗉𝗉𝖾𝗇𝖽:𝐹𝖺𝗉𝗉. With arguments in that order, the two written row maps are represented by 𝖺𝗉𝗉𝖾𝗇𝖽(𝐴,.𝟢,𝑛,𝗏𝗇𝗂𝗅,𝑦𝑠)=𝑦𝑠,𝖺𝗉𝗉𝖾𝗇𝖽(𝐴,.𝗌𝗎𝖼(𝑘),𝑛,𝗏𝖼𝗈𝗇𝗌(𝑘,𝑎,𝑥𝑠),𝑦𝑠)=𝗏𝖼𝗈𝗇𝗌(𝑛+𝑘,𝑎,𝖺𝗉𝗉𝖾𝗇𝖽(𝐴,𝑘,𝑛,𝑥𝑠,𝑦𝑠)). The dots record the equations 𝑚 =𝟢 and 𝑚 =𝗌𝗎𝖼(𝑘) forced by the constructor result indices. They do not request a split on 𝑚. In this declaration 𝐴,𝑚,𝑛, and the constructor index 𝑘 are erased; the vector values and their elements are runtime. The compiler splits the runtime vector, not the inaccessible length.
In particular, put Θ𝑠:=(𝐴:U𝑖)𝗂𝗆𝗉,𝖾𝗋𝖺𝗌𝖾𝖽,(𝑘:ℕ)𝗂𝗆𝗉,𝖾𝗋𝖺𝗌𝖾𝖽,(𝑛:ℕ)𝗂𝗆𝗉,𝖾𝗋𝖺𝗌𝖾𝖽,(𝑎:𝐴)𝖾𝗑𝗉,𝗋𝗎𝗇𝗍𝗂𝗆𝖾,(𝑥𝑠:𝖵𝖾𝖼(𝐴,𝑘))𝖾𝗑𝗉,𝗋𝗎𝗇𝗍𝗂𝗆𝖾,(𝑦𝑠:𝖵𝖾𝖼(𝐴,𝑛))𝖾𝗑𝗉,𝗋𝗎𝗇𝗍𝗂𝗆𝖾. Put Γ𝑠:=𝖺𝗉𝗉𝖾𝗇𝖽:𝐹𝖺𝗉𝗉,Θ𝑠,𝑢𝑠:=𝖺𝗉𝗉𝖾𝗇𝖽@Δ𝖺𝗉𝗉(𝐴,𝑘,𝑛,𝑥𝑠,𝑦𝑠),𝑒𝗋𝖺𝗐𝑠:=𝗏𝖼𝗈𝗇𝗌(𝑛+𝑘,𝑎,𝑢𝑠). The successor right side has the explicit derivations Γ𝑠⊢𝑢𝑠:𝖵𝖾𝖼(𝐴,𝑛+𝑘),Γ𝑠⊢𝑒𝗋𝖺𝗐𝑠:𝖵𝖾𝖼(𝐴,𝑛+𝗌𝗎𝖼(𝑘)). The constructor has result type 𝖵𝖾𝖼(𝐴,𝗌𝗎𝖼(𝑛 +𝑘)), which converts to the displayed result by construction 28.23.
★★☆ Replace .𝗌𝗎𝖼(𝑘) in the second append row by .𝑘. Run the index constraint generated by the vector constructor and identify the judgmental equality that the inaccessible-pattern check would require. State the diagnostic with the forced and written terms. (A quarter page.)
Referenced from 3 locations
From a matrix to a case tree
The compiler carries a frontier telescope, the typed argument context at one matrix node, rather than a list of untyped columns. When a split introduces constructor arguments, their declarations replace the selected declaration in that telescope. Later column types are simultaneously specialized by the unifier substitution. This dependency invariant is the part lost by a compiler that treats the matrix as a rectangular array of names.
For append, the naive rectangular step would replace the vector pattern by its three subpatterns but retain the old columns: (𝐴,𝑚,𝑥𝑠,𝑛,𝑦𝑠)⟶(𝐴,𝑚,𝑘,𝑎,𝑧𝑠,𝑛,𝑦𝑠). The boxes mark the selected column and the entries incorrectly put in its place; they are not an additional pattern form. The right tuple no longer has the frontier’s arity, 𝑘,𝑎,𝑧𝑠 have no declarations there, and the result type still mentions unspecialized 𝑚. The typed step instead applies [𝗌𝗎𝖼(𝑘)/𝑚], replaces the vector declaration by 𝑘 :ℕ,𝑎 :𝐴,𝑧𝑠 :𝖵𝖾𝖼(𝐴,𝑘), and substitutes through the result type. This is the exact point at which an untyped rectangle fails.
A typed case tree for a frontier Θ, a frontier map 𝜌 :Θ →Δ, and result 𝐵[𝜌] is generated by the following forms.
𝗅𝖾𝖺𝖿(𝑖,𝑒) records the least surviving source row 𝑖 and a derivation 𝑓 :𝐹Δ,Θ ⊢𝑒 :𝐵[𝜌]. In a nonrecursive declaration, 𝑓 is not free in 𝑒.
𝗌𝗉𝗅𝗂𝗍(𝑥,{𝑐 ↦(𝜎𝑐,C𝑐)}) requires 𝑥 :𝐷(⃗𝑢) in Θ. For every constructor 𝑐 :(⃗𝑦 :Δ𝑐) →𝐷(⃗𝑣𝑐), restricted unification of (⃗𝑢;𝑥) ≡Ξ;𝐷(⃗𝑣𝑐;𝑐(⃗𝑦)) is either positive or negative. A positive result supplies the dependency-preserving substitution 𝜎𝑐 and the subtree C𝑐 at the specialized frontier. A negative result supplies a conflict or cycle certificate and has no subtree.
𝖺𝖻𝗌𝗎𝗋𝖽(𝑥,{𝜈𝑐}) records a negative certificate 𝜈𝑐 for every constructor of the family of 𝑥.
There is no node for a stuck unification problem. Reading the branches in constructor declaration order fixes a printed representation, while source row order fixes leaf priority.
Referenced from 4 locations
A typed case tree is valid when:
every split result is positive with its typed substitution, or negative with a conflict or cycle certificate; no stuck result occurs;
every specialized leaf has the checked result type at its frontier;
positive and negative alternatives together account for every declared constructor of the selected family, in declaration order; and
every occurrence of 𝑓 in a recursive leaf is a saturated call, and its designated argument uses the direct-child component supplied by the corresponding structural eliminator together with the branch-path child certificate.
These are the four premises of the indexed valid-tree interface used by theorem 78.19, instantiated here by ordered Timpl-clauses rows.
Referenced from 4 locations
This chapter gives the transition system of definition 78.9 one fixed schedule. Maintain an ordered equation list, always inspect its leftmost equation, and use deterministic weak-head forms. Tag a variable old when it was in the frontier before the selected constructor split and fresh when it belongs to that constructor’s telescope. For an equation between two distinct variables, list the two possible orientations in this order: eliminate a fresh variable before an old one, and otherwise eliminate the variable later in the ordered frontier telescope before the earlier one. An orientation is admissible only when its occurs check succeeds and the following stable move is legal. For a candidate 𝑥 :=𝑡, move 𝑥 rightward to immediately after the rightmost declaration free in 𝑡, if any such declaration is later than 𝑥, crossing declarations one at a time and preserving the order of every other declaration. The move is legal exactly when every crossed declaration is independent of 𝑥; it is then unique. Choose the first admissible orientation. Thus an injectivity equation 𝑟 =𝑞, with old 𝑟 and fresh 𝑞, has the canonical solution 𝑞 :=𝑟. For any other equation whose left side is not a variable and whose right side is, orient that right-hand variable to the left; then try the solution transition, the indexed self-unifiability check followed by injectivity, conflict, and cycle, in that order. If none applies, return the remaining ordered list as stuck. Equations exposed by an injectivity step replace the selected equation in constructor-telescope order. A solution in any equation uses the same stable move and is applied immediately to the telescope and the whole remaining list. An equation 𝑥 =𝑥 is not a distinct-variable equation and remains stuck unless a constructor rule changes its form; the schedule adds no reflexive deletion. The recursive index self-check uses this same schedule.
This policy makes every finite transition trace and every returned answer unique. It does not add reflexive deletion, and it is not a local proof that all weak-head computations or recursively requested index self-checks terminate. The totality result below therefore states that missing premise explicitly.
Referenced from 4 locations
The split node is both an execution plan and a proof plan. At run time a constructor value selects one subtree. In the kernel translation the same node becomes one application of the family eliminator; its motive contains the frontier substitution and the homogeneous equality constraints.
Let 𝑀 be an ordered matrix at a typed frontier. The partial function 𝖼𝗈𝗆𝗉𝗂𝗅𝖾(𝑀) has exactly the following result forms: 𝑅::=𝗈𝗄(C)∣𝗎𝗇𝖼𝗈𝗏𝖾𝗋𝖾𝖽(Θ,𝜋)∣𝗌𝗍𝗎𝖼𝗄𝖤𝗊(E)∣𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾(𝑖,𝑧,𝑐,𝑢)∣𝖻𝖺𝖽𝖣𝗈𝗍(𝑖,𝑢,𝑡,𝐴)∣𝖻𝖺𝖽𝖠𝖻𝗌𝗎𝗋𝖽(𝑖,𝑐,𝜋)∣𝖻𝖺𝖽𝖱𝖾𝗅𝖾𝗏𝖺𝗇𝖼𝖾(𝑖,𝑧). Here 𝜋 is the constructor path, E is the ordered unsolved unification problem, and 𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾(𝑖,𝑧,𝑐,𝑢) says that row 𝑖 demands head 𝑐 at the eliminated declaration 𝑧, but its typed forced image 𝑢 is neutral. The remaining three errors carry, respectively, the forced and written terms at their type, a reachable constructor and path, or the erased blocking declaration. There are no implicit abort outcomes. The function is defined as follows.
If 𝑀 is empty, return 𝗎𝗇𝖼𝗈𝗏𝖾𝗋𝖾𝖽(Θ,𝜋) for frontier Θ and constructor path 𝜋.
Apply ordered-row priority before inspecting later assertions. If the first surviving row carries a row-local reachable-absurd marker, take its leftmost marker and return 𝖻𝖺𝖽𝖠𝖻𝗌𝗎𝗋𝖽(𝑖,𝑐,𝜋) using the constructor recorded by the marker. If it carries a suspended forced match, retry the leftmost such task’s forced-image matcher after the accumulated substitution. A matching constructor consumes that task structurally; a different head deletes the row and restarts priority; a still-neutral image returns 𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾(𝑖,𝑧,𝑐,𝑢).
If the first row has no suspended forced match and no unresolved constructor or absurd pattern, turn each remaining dot cell into the equality between its image under the accumulated frontier substitution and its written term. Check only that row’s equality obligations, in list order, against the accumulated substitution. If they hold, complete its partial pattern-variable assignment to 𝜏ℓ, return 𝗈𝗄(𝗅𝖾𝖺𝖿(𝑖,𝑒𝑖[𝜏𝑓ℓ])), and discard every later row without validating any dot or absurd assertion in those rows. The factorization needed to type this leaf is lemma 121.15. If an obligation of the first row is not forced, return 𝖻𝖺𝖽𝖣𝗈𝗍(𝑖,𝑢,𝑡,𝐴).
The returned tree carries no redundancy warning: Timpl-clauses accepts an unreachable later row silently because ordered priority never selects it.
Otherwise scan the patterns of that first surviving row from left to right and select its leftmost blocking pattern, in the sense of definition 121.1. Encountering an unresolved constructor or absurd pattern in an erased column returns 𝖻𝖺𝖽𝖱𝖾𝗅𝖾𝗏𝖺𝗇𝖼𝖾(𝑖,𝑧).
If the leftmost blocking column contains 𝑥 :𝐷(⃗𝑢), enumerate the constructors of 𝐷. For each constructor 𝑐, run restricted unification with the schedule of definition 121.11 on (⃗𝑢;𝑥) ≡Ξ;𝐷(⃗𝑣𝑐;𝑐(⃗𝑦)). A stuck result returns 𝗌𝗍𝗎𝖼𝗄𝖤𝗊(E) with the unsolved equation list. A negative result is recorded in the node. For a positive result, specialize the selected pattern cell exactly once, in original row order, against 𝑐(⃗𝑦), by the following four exhaustive clauses.
A selected 𝑐(𝑝1,…,𝑝𝑘) contributes its 𝑘 =|Δ𝑐| subpatterns; a selected 𝑑(⃗𝑝) with 𝑑 ≠𝑐 deletes the row.
A selected variable row is retained, records the binding 𝑥 :=𝑐(⃗𝑦), and contributes the fresh variable-pattern tuple ⃗𝑦 of length |Δ𝑐|.
A selected inaccessible row .𝑡 is retained with the residual obligation 𝑐(⃗𝑦) ≡𝑡, after applying the positive substitution to both sides, and contributes the fresh variable-pattern tuple ⃗𝑦. Later specialization continues to substitute through the obligation. It is checked only if that row becomes the first nonblocking candidate; judgmental equality then discharges it, while failure reports the forced and written terms.
A selected absurd row is retained with a row-local reachable-absurd marker in every positive constructor branch and contributes the fresh variable-pattern tuple ⃗𝑦. The recursive compiler invocation raises the marker only if that row becomes the least surviving candidate. A prior successful row instead discards it as redundant. The same priority convention applies to an invalid dot row.
After row specialization, apply 𝜎𝑐 to the frontier and row annotations. This frontier contains both surviving old declarations and the newly introduced constructor-telescope declarations. For every declaration 𝑧 eliminated by 𝜎𝑐 after the selected cell has been expanded, run the recursive forced-image matcher 𝖿𝗈𝗋𝖼𝖾𝜎𝑐(𝑝𝑧,𝜎𝑐(𝑧)). A variable records its forced image; a dot records their residual judgmental equality; an absurd pattern records a reachable-absurd marker; and a constructor pattern requires the forced image to expose the same head and recursively matches its subpatterns against the forced constructor arguments. Different heads delete the row. A neutral forced image against a constructor pattern stores the typed suspended task 𝑐(⃗𝑝)𝖿𝗈𝗋𝖼𝖾𝖽𝖡𝗒𝑢; it is retried, and can return 𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾, only if that row becomes the first surviving candidate. This matcher consumes the one pattern cell for 𝑧 and creates no frontier cell. In particular, the append successor branch uses 𝑚 :=𝗌𝗎𝖼(𝑘) to validate and remove .𝗌𝗎𝖼(𝑘); it does not expose a second 𝑘-column.
Thus a retained row replaces the selected pattern by exactly |Δ𝑐| patterns and removes one pattern for every other declaration eliminated by 𝜎𝑐. The specialized frontier performs the same replacement and removals, so row and frontier arities agree. Recursively compile the resulting specialized matrix. Negative constructor branches have no matrix and therefore perform none of these row actions.
If every constructor is negative, return 𝗈𝗄(𝖺𝖻𝗌𝗎𝗋𝖽(𝑥,{𝜈𝑐})). Otherwise return 𝗈𝗄 of the split node after every positive branch has compiled. A positive branch with an empty specialized matrix returns 𝗎𝗇𝖼𝗈𝗏𝖾𝗋𝖾𝖽 with that constructor appended to the path. Any other diagnostic returned by a recursive branch propagates unchanged.
Referenced from 5 locations
The algorithm never guesses a later split in order to escape a stuck leftmost one. The declaration order of rows, columns, and constructors together with definition 121.11 therefore gives at most one result.
For a finite well-scoped Timpl-clauses matrix, suppose every restricted-unifier invocation made by 𝖼𝗈𝗆𝗉𝗂𝗅𝖾, including its recursive index self-checks and required weak-head computations, terminates. Then compilation terminates in exactly one of the seven result forms displayed in definition 121.12.
Referenced from 7 locations
Proof of Lemma 121.13 — Termination of matrix compilation, relative form
Proof. The forced-image matcher terminates structurally on the consumed pattern, returning a resolved state, deletion, or one suspended task. A suspended task is retried only after its row becomes first; that retry either consumes the task or immediately returns 𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾. For a matrix 𝑀, let 𝜇(𝑀) be the total number of constructor and absurd nodes in all its patterns. A recursive call is made only after a split. In a fixed positive constructor branch, a row headed by that constructor loses its outer constructor node and retains only the nodes already counted in its subpatterns. A row headed by another constructor disappears. A variable row adds no constructor node, and an inaccessible row adds none. At least one row made the selected column blocking; in the chosen branch that row either loses its outer node or disappears. Thus every recursive call has strictly smaller 𝜇. All other operations traverse finite telescopes, rows, constructor lists, terms, or one of the terminating restricted-unifier runs assumed in the statement. Induction on 𝜇(𝑀) proves termination. ◻
★★☆ A variable row is copied into every positive constructor branch. Explain why counting rows does not prove lemma 121.13, and verify that 𝜇 decreases in each branch of a matrix containing the two patterns 𝗏𝖼𝗈𝗇𝗌(𝑘,𝑎,𝑥𝑠) and a variable. (A quarter page.)
Referenced from 3 locations
The append trace
The first two append columns contain 𝐴 and the inaccessible index 𝑚, so neither blocks. The vector column is the leftmost blocking column. Splitting 𝑥𝑠 :𝖵𝖾𝖼(𝐴,𝑚) produces the two constraint calculations 𝑚=𝟢has solution[𝟢/𝑚],𝑚=𝗌𝗎𝖼(𝑘)has solution[𝗌𝗎𝖼(𝑘)/𝑚]. Both are solution transitions of the restricted unifier. In the first branch the successor row disappears and the dot .𝟢 is forced. In the second branch the 𝗏𝗇𝗂𝗅 row disappears and the dot .𝗌𝗎𝖼(𝑘) is forced. In each retained row the forced-image matcher consumes the old 𝑚-cell. The successor frontier therefore contains the constructor index 𝑘 once, not once from the vector split and again from matching the dot. Each specialized matrix has one unblocked row, so the compiler returns 𝗈𝗄(C𝖺𝗉𝗉𝖾𝗇𝖽). Put 𝜎0:=[𝟢/𝑚,𝗏𝗇𝗂𝗅/𝑥𝑠],𝜎𝑠:=[𝗌𝗎𝖼(𝑘)/𝑚,𝗏𝖼𝗈𝗇𝗌(𝑘,𝑎,𝑧𝑠)/𝑥𝑠],C0:=𝗅𝖾𝖺𝖿(1,𝑦𝑠),𝑒𝑠(𝑘,𝑎,𝑧𝑠):=𝗏𝖼𝗈𝗇𝗌(𝑛+𝑘,𝑎,𝖺𝗉𝗉𝖾𝗇𝖽@Δ𝖺𝗉𝗉(𝐴,𝑘,𝑛,𝑧𝑠,𝑦𝑠)),C𝑠(𝑘,𝑎,𝑧𝑠):=𝗅𝖾𝖺𝖿(2,𝑒𝑠(𝑘,𝑎,𝑧𝑠)). Then C𝖺𝗉𝗉𝖾𝗇𝖽:=𝗌𝗉𝗅𝗂𝗍(𝑥𝑠,{𝗏𝗇𝗂𝗅↦(𝜎0,C0),𝗏𝖼𝗈𝗇𝗌↦(𝜎𝑠,C𝑠)}). The branch key is the constructor name. Its declared telescope binds 𝑘,𝑎,𝑧𝑠 in 𝜎𝑠 and C𝑠; those variables are not part of the key.
To translate the tree, put Δ𝑛,𝑦𝑠:=(𝑛:ℕ)𝖾𝗑𝗉,𝖾𝗋𝖺𝗌𝖾𝖽,(𝑦𝑠:𝖵𝖾𝖼(𝐴,𝑛))𝖾𝗑𝗉,𝗋𝗎𝗇𝗍𝗂𝗆𝖾. Then 𝑃(𝑚,𝑥𝑠):=ΠΔ𝑛,𝑦𝑠𝖵𝖾𝖼(𝐴,𝑛+𝑚). Write 𝐷𝐴(𝑞):=𝖵𝖾𝖼(𝐴,𝑞). At a successor constructor, the defining equation of 𝖡𝖾𝗅𝗈𝗐𝐷𝐴 is 𝖡𝖾𝗅𝗈𝗐𝐷𝐴(𝑃,𝗌𝗎𝖼(𝑘),𝗏𝖼𝗈𝗇𝗌(𝑘,𝑎,𝑧𝑠))≡𝖡𝖾𝗅𝗈𝗐𝐷𝐴(𝑃,𝑘,𝑧𝑠)×𝑃(𝑘,𝑧𝑠). Let 𝐻𝑠:𝖡𝖾𝗅𝗈𝗐𝐷𝐴(𝑃,𝗌𝗎𝖼(𝑘),𝗏𝖼𝗈𝗇𝗌(𝑘,𝑎,𝑧𝑠)). The recursive-result component of 𝐻𝑠 is 𝑟𝑠:=𝗉𝗋2(𝐻𝑠):𝑃(𝑘,𝑧𝑠),𝑃(𝑘,𝑧𝑠)≡ΠΔ𝑛,𝑦𝑠𝖵𝖾𝖼(𝐴,𝑛+𝑘). For fixed 𝐴, let 𝑝0 and 𝑝𝑠 be the following fully annotated methods: 𝑝0:=𝜆Δ𝑛,𝑦𝑠𝑦𝑠,𝑝𝑠(𝑘,𝑎,𝑧𝑠,𝑟):=𝜆Δ𝑛,𝑦𝑠𝗏𝖼𝗈𝗇𝗌(𝑛+𝑘,𝑎,𝑟@Δ𝑛,𝑦𝑠(𝑛,𝑦𝑠)). Here 𝑘,𝑎,𝑧𝑠,𝑟 are the four declarations added to the successor method’s checking context by Vec-elim; 𝑘 is erased, while 𝑎,𝑧𝑠,𝑟 are runtime. The argument 𝑟 is exactly the component 𝑟𝑠 selected from 𝐻𝑠, rather than an untyped recursive call. Define 𝖺𝗉𝗉𝖾𝗇𝖽†𝐴(𝑚,𝑛,𝑥𝑠,𝑦𝑠):=𝗏𝗂𝗇𝖽(𝑃;𝑝0;𝑝𝑠;𝑚,𝑥𝑠)@Δ𝑛,𝑦𝑠(𝑛,𝑦𝑠). The closed target obtained by theorem 121.18 is the fully annotated core term 𝑓†:=𝜆Δ𝖺𝗉𝗉𝖺𝗉𝗉𝖾𝗇𝖽†𝐴(𝑚,𝑛,𝑥𝑠,𝑦𝑠). Let 𝑚𝖺𝗉𝗉𝑠 be the proof-dependent recursive step induced by 𝑝0,𝑝𝑠 in the general lowering construction. Put 𝐻0𝑠:=𝖻𝖾𝗅𝗈𝗐𝐷𝐴(𝑃,𝑚𝖺𝗉𝗉𝑠,𝗌𝗎𝖼(𝑘),𝗏𝖼𝗈𝗇𝗌(𝑘,𝑎,𝑧𝑠)),𝑟0𝑠:=𝗉𝗋2(𝐻0𝑠). Write (PA) for the instance of (78.16) at the direct child 𝑧𝑠. Then 𝑟0𝑠@Δ𝑛,𝑦𝑠(𝑛,𝑦𝑠)(PA)≡𝑓†@Δ𝖺𝗉𝗉(𝐴,𝑘,𝑛,𝑧𝑠,𝑦𝑠)𝐵𝑒𝑡𝑎⟶∗𝖺𝗉𝗉𝖾𝗇𝖽†𝐴(𝑘,𝑛,𝑧𝑠,𝑦𝑠). Consequently the transformed successor leaf is 𝑒𝑠(𝑘,𝑎,𝑧𝑠)[𝑓†/𝖺𝗉𝗉𝖾𝗇𝖽](PA)≡𝗏𝖼𝗈𝗇𝗌(𝑛+𝑘,𝑎,𝑟0𝑠@Δ𝑛,𝑦𝑠(𝑛,𝑦𝑠)), which is the body of 𝑝𝑠 at its canonical recursive-result component. In the successor method, the displayed erased/runtime applications of 𝑟 have type 𝖵𝖾𝖼(𝐴,𝑛 +𝑘). The constructor result has length 𝗌𝗎𝖼(𝑛 +𝑘), judgmentally equal to 𝑛 +𝗌𝗎𝖼(𝑘) by construction 28.23, which recurs on its second argument. The same definition gives 𝑛 +𝟢 ≡𝑛, typing the base method. Thus the motive, rather than an inserted cast, checks either branch.
Let 𝑥𝑠2:=𝗏𝖼𝗈𝗇𝗌(𝗌𝗎𝖼(𝟢),𝑎,𝗏𝖼𝗈𝗇𝗌(𝟢,𝑏,𝗏𝗇𝗂𝗅)),𝑦𝑠1:=𝗏𝖼𝗈𝗇𝗌(𝟢,𝑐,𝗏𝗇𝗂𝗅),𝑟2:=𝖺𝗉𝗉𝖾𝗇𝖽†𝐴(𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)),𝗌𝗎𝖼(𝟢),𝑥𝑠2,𝑦𝑠1),𝑟1:=𝖺𝗉𝗉𝖾𝗇𝖽†𝐴(𝗌𝗎𝖼(𝟢),𝗌𝗎𝖼(𝟢),𝗏𝖼𝗈𝗇𝗌(𝟢,𝑏,𝗏𝗇𝗂𝗅),𝑦𝑠1),𝑟0:=𝖺𝗉𝗉𝖾𝗇𝖽†𝐴(𝟢,𝗌𝗎𝖼(𝟢),𝗏𝗇𝗂𝗅,𝑦𝑠1). Using the two vector constructor equations Vec-comp of chapter 31 and the addition equations of construction 28.23, the three root computations are 𝑟2𝑉𝑒𝑐−𝑐𝑜𝑚𝑝; 𝑐𝑜𝑛𝑠𝑡𝑟𝑢𝑐𝑡𝑖𝑜𝑛28.23⟶∗𝗏𝖼𝗈𝗇𝗌(𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)),𝑎,𝑟1),𝑟1𝑉𝑒𝑐−𝑐𝑜𝑚𝑝; 𝑐𝑜𝑛𝑠𝑡𝑟𝑢𝑐𝑡𝑖𝑜𝑛28.23⟶∗𝗏𝖼𝗈𝗇𝗌(𝗌𝗎𝖼(𝟢),𝑏,𝑟0),𝑟0𝑉𝑒𝑐−𝑐𝑜𝑚𝑝; 𝑐𝑜𝑛𝑠𝑡𝑟𝑢𝑐𝑡𝑖𝑜𝑛28.23⟶∗𝑦𝑠1. Compatible closure of the latter two computations gives the closed endpoint 𝑟2⟶∗𝗏𝖼𝗈𝗇𝗌(𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)),𝑎,𝗏𝖼𝗈𝗇𝗌(𝗌𝗎𝖼(𝟢),𝑏,𝑦𝑠1)). Every step is a target eliminator computation on closed constructor data.
What successful compilation proves
Four facts must be separated. Specialization preserves the residual-row invariant. A selected row then factors through its raw written map. Clause compilation produces a typed case tree with first-match behavior. Only a second translation lowers that typed tree to eliminators.
Suppose the residual state of raw row 𝑖 satisfies the row-map invariant at frontier 𝜌 :Θ →Δ. If a positive constructor split returns the dependency-preserving substitution 𝜎 :Θ′ →Θ and specialization retains this row, then the resulting state satisfies the row-map invariant at 𝜌𝜎 :Θ′ →Δ. Its old obligations are transported by 𝜎, and a selected or forced-image dot contributes the typed equality between its forced image and its written term. If the retained body has derivation 𝑓 :𝐹Δ,Θ ⊢𝑒 :𝐵[𝜌], substitution by the identity extension 𝜎𝑓 gives 𝑓:𝐹Δ,Θ′⊢𝑒[𝜎𝑓]:𝐵[𝜌𝜎].
If either the selected-pattern comparison or a forced-image comparison exposes distinct constructor heads, specialization instead deletes the row. A deleted row contributes no leaf or assertion to the branch. If a forced constructor comparison has a neutral image, specialization retains the row with its typed suspended forced-match obligation; it assumes no constructor equality.
Referenced from 7 locations
Proof of Lemma 121.14 — Specialization preserves the row-map invariant
Proof. The restricted unifier returns a well-typed substitution for the entire frontier telescope. For a constructor pattern, its literal factorization replaces the selected variable by the constructor applied to its fresh arguments, so matching the residual subpatterns is equivalent to matching the old constructor cell. A variable pattern records that constructor image and puts one fresh variable pattern at every declaration of the constructor telescope. A selected dot .𝑡 records the residual equality between the constructor image and 𝑡[𝜎]; using that equality restores exactly the dot component of ̂𝜌𝑖. An absurd pattern retains a reachable-absurd marker in a positive branch. Hence the selected cell is consumed once and replaced by exactly |Δ𝑐| cells, matching the constructor telescope. For another declaration eliminated by 𝜎, structural induction on its pattern proves the forced-image matcher sound: matching heads recurse without adding frontier cells, variables record their images, dots retain obligations, and absurd patterns retain markers. A neutral image against a constructor stores exactly the forced-match premise needed by the row-map invariant. That cell and its eliminated declaration are both removed. Constructor disjointness justifies deletion at a different head in either matcher. The recursive compiler call applies ordered priority before either validating an obligation or raising a marker; neither becomes a run-time test. Composing a hypothetical residual match with 𝜎, and then applying the old row-map invariant, gives ̂𝜌𝑖𝜏 ≡𝜌𝜎𝜐, the required new invariant. The substitution lemma applied to 𝜎𝑓 preserves the declaration 𝑓 :𝐹Δ and gives the displayed specialized-body judgment; 𝐹Δ is closed with respect to the frontier because the declarations of Δ are bound by its iterated products. These cases exhaust the pattern grammar. ◻
Suppose compilation reaches a leaf frontier Θℓ with path map 𝜌ℓ :Θℓ →Δ, and the least nonblocking state is raw row 𝑖. If all its residual equality and forced-match obligations are discharged, then compilation constructs a typed map 𝜏ℓ:Θℓ→Θ𝑖such that̂𝜌𝑖𝜏ℓ≡𝜌ℓ. Consequently substitution and conversion give 𝑓:𝐹Δ,Θℓ⊢𝑒𝑖[𝜏𝑓ℓ]:𝐵[𝜌ℓ]. No suspended forced match, dot, or absurd assertion in a later shadowed row is needed for either conclusion.
Referenced from 12 locations
Proof of Lemma 121.15 — Selected-row factorization
Proof. The residual row has no constructor, forced-match, or absurd blocker. Assign each remaining linear variable pattern to its frontier variable and combine these assignments with the partial assignments accumulated along the path. This constructs 𝜏ℓ. Every remaining dot and forced-match obligation has been discharged, so the row-map invariant preserved by lemma 121.14, with 𝜐 the identity substitution, gives ̂𝜌𝑖𝜏ℓ ≡𝜌ℓ. Applying substitution to the raw body derivation gives 𝑒𝑖[𝜏𝑓ℓ] :𝐵[̂𝜌𝑖𝜏ℓ] under 𝑓 :𝐹Δ,Θℓ; conversion gives the displayed type. The identity extension is necessary: substituting only 𝜏ℓ would not have the recursive identifier in its source or target context. Ordered priority stops before consulting any later row. ◻
Let 𝑥𝑗 :𝐷(⃗𝑣) be the designated structural argument in Δ, and let 𝑃 be the motive used to lower a valid recursive case tree. Suppose a leaf at 𝜌ℓ :Θℓ →Δ has a body derivation 𝑓:𝐹Δ,Θℓ⊢𝑒ℓ:𝐵[𝜌ℓ], and every occurrence 𝑓@Δ(⃗𝑟) in 𝑒ℓ is saturated. Suppose also that its designated argument 𝑟𝑗 :𝐷(⃗𝑤) is a direct child certified by the branch path. For 𝐻ℓ:𝖡𝖾𝗅𝗈𝗐𝐷(𝑃,(⃗𝑣;𝑥𝑗)[𝜌ℓ]), replace such an occurrence by the corresponding component 𝜋𝐻ℓ(⃗𝑟,𝑞):𝐵[⃗𝑟],𝑞:(⃗𝑤;𝑟𝑗)≡Ξ;𝐷(⃗𝑣;𝑥𝑗)[⃗𝑟]. Here 𝑞 is the reflexivity certificate obtained after substituting the recursive call tuple ⃗𝑟; its designated component is 𝑟𝑗. The resulting leaf 𝑒♯ℓ(𝐻ℓ) has derivation Θℓ,𝐻ℓ:𝖡𝖾𝗅𝗈𝗐𝐷(𝑃,(⃗𝑣;𝑥𝑗)[𝜌ℓ])⊢𝑒♯ℓ(𝐻ℓ):𝐵[𝜌ℓ]. Let 𝑚 be the case-tree method and 𝑚𝑠 its proof-dependent recursive step in the lowering construction. Put 𝐻0ℓ:=𝖻𝖾𝗅𝗈𝗐𝐷(𝑃,𝑚𝑠,⃗𝑣[𝜌ℓ],𝑥𝑗[𝜌ℓ]). Let 𝑓† :𝐹Δ be the lowered function. Then 𝑒♯ℓ(𝐻ℓ)[𝐻0ℓ/𝐻ℓ]≡𝑒ℓ[𝑓†/𝑓].
Referenced from 3 locations
Proof of Lemma 121.16 — Recursive-leaf replacement through Below
Proof. Use rule induction on the displayed derivation, strengthened to an arbitrary well-typed subterm after a substitution for its non-𝑓 variables. Treat a maximal saturated spine headed by 𝑓 as one derived application-spine case before descending into ordinary application premises. The source-card check rules out every other occurrence of 𝑓. In the derived case, the direct-child certificate selects from 𝐻ℓ a component with exactly the displayed type 𝐵[⃗𝑟], so replacing the occurrence preserves its type. On the canonical package, write (R) for the defining equation of 𝗋𝖾𝖼𝐷 and (J) for the reflexivity equation of homogeneous identity elimination. Write (P) for (78.16), instantiated with result family 𝐵. The branch-path certificate computes to homogeneous reflexivity, and the selected component calculates as 𝜋𝐻0ℓ(⃗𝑟,―――𝗋𝖾𝖿𝗅)(R)⟶∗𝑚𝑠((⃗𝑤;𝑟𝑗),𝖻𝖾𝗅𝗈𝗐𝐷(𝑃,𝑚𝑠,⃗𝑤,𝑟𝑗),⃗𝑟,―――𝗋𝖾𝖿𝗅)(J)⟶∗𝑚⃗𝑟𝖻𝖾𝗅𝗈𝗐𝐷(𝑃,𝑚𝑠,⃗𝑤,𝑟𝑗)(P)≡𝑓†@Δ(⃗𝑟).
For a variable other than 𝑓, a constructor, or a constant, the translation is the identity. Universe and type-former cases translate their typed operands by the induction hypotheses. In an application whose head is not the saturated recursive identifier, the two induction hypotheses translate the function and argument; the explicitness and relevance annotations are unchanged. Product, pair, projection, and eliminator cases apply the induction hypotheses to every typed premise. In a binder case, choose a representative whose binder avoids 𝑓, 𝐻ℓ, and the free variables of 𝜌ℓ, and apply the strengthened induction hypothesis in the extended context. For a substituted subterm, identity extension across 𝑓 commutes with the non-𝑓 substitution, while the replacement substitution maps 𝑓 to the closed 𝑓†. The conversion case follows from congruence and the unchanged result type 𝐵[𝜌ℓ]. These are all Timpl term and typing-rule families. Congruence combines the displayed component calculation at every recursive occurrence and proves the final judgmental equality. ◻
Let 𝑓 :𝐹Δ be a Timpl-clauses declaration. If every source row is well scoped and its right side checks as in definition 121.8, and if 𝖼𝗈𝗆𝗉𝗂𝗅𝖾(𝑀) =𝗈𝗄(C), then C is a typed valid case tree for that declaration. At a leaf for row 𝑖, the stored body is 𝑒𝑖[𝜏𝑓ℓ] under 𝑓 :𝐹Δ, at the path type 𝐵[𝜌ℓ], where 𝜏ℓ is the map of lemma 121.15. For a recursive declaration, every leaf occurrence satisfies the designated direct-child condition of definition 121.10.
Referenced from 5 locations
Proof of Theorem 121.17 — Compilation typing
Proof. A returned result is a finite derivation of 𝖼𝗈𝗆𝗉𝗂𝗅𝖾(𝑀) =𝗈𝗄(C) with a completed call tree. Induct on that derivation; this does not use the relative totality lemma. At a positive split, lemma 121.14 preserves every retained row state, and the induction hypothesis types every subtree at its specialized frontier. At a leaf, lemma 121.15 supplies both the map to the raw pattern context and the checked body under 𝑓 :𝐹Δ at the path type. Every specialization uses the identity extension across 𝑓 supplied by lemma 121.14; hence no recursive-identifier hypothesis is dropped between the raw row and the leaf. Every negative branch has the conflict or cycle certificate required by definition 121.9, and an absurd node has such a certificate for every constructor. An uncovered branch, 𝗌𝗍𝗎𝖼𝗄𝖤𝗊, 𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾, 𝖻𝖺𝖽𝖣𝗈𝗍, 𝖻𝖺𝖽𝖠𝖻𝗌𝗎𝗋𝖽, or 𝖻𝖺𝖽𝖱𝖾𝗅𝖾𝗏𝖺𝗇𝖼𝖾 would have returned its named diagnostic rather than 𝗈𝗄(C). Thus unifier outcomes justify every branch, specialization types every leaf, and constructor enumeration is exhaustive. These are the first three clauses of definition 121.10. The source card checks every occurrence of 𝑓 as a saturated direct-child call, and the branch path retains its child certificate. This establishes the recursive-decrease clause. ◻
Let C be any typed valid Timpl-clauses case tree for 𝑓 :𝐹Δ, independently of how that tree was constructed. Then its lowering through the declared Timpl eliminators is a term ⋅⊢𝑓†:𝐹Δ,𝑓†:=𝗅𝗈𝗐𝖾𝗋(C). For a leaf at path map 𝜌ℓ :Θℓ →Δ storing 𝑓:𝐹Δ,Θℓ⊢𝑒ℓ:𝐵[𝜌ℓ], lowering has the judgmental computation 𝑓†(⃗𝑥[𝜌ℓ])≡𝑒ℓ[𝑓†/𝑓]. The substitution [𝑓†/𝑓] is well typed because the source and target of the substituted identifier are both 𝐹Δ. On a closed ready tuple following that path, the corresponding family and identity eliminator computations form a finite target reduction to the closed instance of 𝑒ℓ[𝑓†/𝑓]. In the recursive case, direct-child calls are replaced by the corresponding 𝖡𝖾𝗅𝗈𝗐𝐷 components recalled in theorem 78.19.
Referenced from 9 locations
Proof of Theorem 121.18 — Case-tree-to-eliminator lowering
Proof. Each validity clause is a hypothesis of theorem 78.19. Its node construction supplies the typed proof-dependent motive and the positive-branch specializers. At a leaf, lemma 121.16 types the replacement of every saturated recursive call by its 𝖡𝖾𝗅𝗈𝗐𝐷 component and proves that the canonical below-package makes that replacement judgmentally equal to 𝑒ℓ[𝑓†/𝑓]. Hence the inherited elimination theorem supplies the displayed type and leaf computation without dropping 𝑓 :𝐹Δ. On a closed ready tuple, each split scrutinee has constructor form. The family eliminator selects the recorded method, and its equality transports compute on reflexivity. Induction on the finite path gives the finite reduction. No raw clause matrix or first-match premise is used in this lowering stage. ◻
The substantive hypotheses have distinct roles. Raw body typing and selected-row factorization are needed for leaf typing; dropping it admits a branch with an arbitrary result. Positive unifier factorization is needed to specialize dependent later columns; an occurs check alone does not produce their types. Restricted unification is needed to avoid K. Finiteness and first-order clauses make matrix recursion well founded; totality still has the explicit unifier-termination premise of lemma 121.13. Neither statement concerns larger pattern languages.
Write 𝖿𝗈𝗅𝗅𝗈𝗐𝗌(C,⃗𝑎;𝑖,𝜉) when the symbolic case-tree dynamics follows the constructor heads of the closed ready tuple ⃗𝑎 to a leaf for row 𝑖, whose residual frontier Θℓ is closed by 𝜉 : ⋅ →Θℓ.
Suppose 𝖼𝗈𝗆𝗉𝗂𝗅𝖾(𝑀)=𝗈𝗄(C). Then every closed well-typed tuple ⃗𝑎 :Δ satisfying definition 121.5, and whose runtime split-family components have canonical constructor form, follows exactly one path. More precisely, row 𝑖 is the least row with 𝗆𝖺𝗍𝖼𝗁𝖾𝗌(⃗𝑝𝑖,⃗𝑎,𝜃) if and only if there is a leaf closure 𝜉 for which 𝖿𝗈𝗅𝗅𝗈𝗐𝗌(C,⃗𝑎;𝑖,𝜉)and𝜃≡𝜏ℓ𝜉, where 𝜏ℓ :Θℓ →Θ𝑖 is the selected-row factorization stored at that leaf. Thus clause-to-tree compilation preserves first-match semantics before any eliminator lowering is chosen.
If compilation returns 𝗎𝗇𝖼𝗈𝗏𝖾𝗋𝖾𝖽(Θ,𝜋), the reported sequence of constructor choices is a well-typed symbolic pattern compatible with the frontier constraints and with no source row. Results 𝗌𝗍𝗎𝖼𝗄𝖤𝗊, 𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾, 𝖻𝖺𝖽𝖣𝗈𝗍, 𝖻𝖺𝖽𝖠𝖻𝗌𝗎𝗋𝖽, and 𝖻𝖺𝖽𝖱𝖾𝗅𝖾𝗏𝖺𝗇𝖼𝖾 are diagnostics, not coverage witnesses.
Referenced from 9 locations
Proof of Theorem 121.19 — First-match simulation and failure witnesses
Proof. Induct on the compiler call tree. In the leaf case, the first surviving row has no constructor, suspended forced-match, or absurd blocker, and successful compilation has validated all its residual obligations. By lemma 121.15, it therefore matches every closing input at that frontier with assignment 𝜏ℓ𝜉 and is the least matching row. Ordered priority discards all later rows before examining their obligations, so a shadowed forced match, invalid dot, or absurd marker cannot change this case.
At a split on a closed runtime value, canonical constructor form selects one declared constructor 𝑐. The value’s indices instantiate the constraint (⃗𝑢;𝑥) ≡Ξ;𝐷(⃗𝑣𝑐;𝑐(⃗𝑦)), so the 𝑐 case cannot have a negative certificate. Successful compilation also rules out both 𝗌𝗍𝗎𝖼𝗄𝖤𝗊 and 𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾. Hence there is one positive 𝑐 subtree. Specialization deletes a row when its selected cell has a different constructor head or when a constructor pattern in another substitution-eliminated column has a different head from that column’s forced image. Either deletion is sound: the row cannot match the present input. For every retained row, structural induction on the selected pattern and on each forced-image task gives the converse correspondence: the original row matches precisely when the specialized row matches the branch tuple and all its residual obligations hold. Variables record their forced images, matching constructor heads recurse, and inaccessible terms add no run-time choice. Both matchers preserve the order of retained rows. This is the dependent instance of the least-row decomposition mechanism in lemma 121.4. The induction hypothesis gives one leaf containing the least matching specialized row, which is the least original row matching the input. The row-map invariant of lemma 121.14 and lemma 121.15 identify its closed assignment as 𝜃 ≡𝜏ℓ𝜉.
At an absurd node, a hypothetical closed tuple would give the selected position canonical form 𝑐(⃗𝑤). Its indices and element instantiate the same constructor constraint, contradicting the recorded negative certificate 𝜈𝑐. Thus no closed tuple reaches an absurd node, and the successful coverage assertion is vacuous in that case.
For 𝗎𝗇𝖼𝗈𝗏𝖾𝗋𝖾𝖽(Θ,𝜋), read the constructor choices on the recursive-call stack from root to failure. Every positive unifier supplies a typed specialization, so their composite types the reported symbolic pattern. The failure occurs precisely when its specialized matrix is empty. Thus no row is compatible with that pattern. A 𝗌𝗍𝗎𝖼𝗄𝖤𝗊 result has no positive or negative certificate; 𝗌𝗍𝗎𝖼𝗄𝖥𝗈𝗋𝖼𝖾 has no constructor head to compare; and the three 𝖻𝖺𝖽 results reject a row against the Timpl-clauses card rather than exhibit an uncovered input. ◻
The theorem does not assert that every symbolic witness has a closed inhabitant; a pattern may retain a variable of an empty type. The successful direction needs no such inhabitance hypothesis.
Suppose 𝖼𝗈𝗆𝗉𝗂𝗅𝖾(𝑀) =𝗈𝗄(C), and put 𝑓†:=𝗅𝗈𝗐𝖾𝗋(C). Let ⃗𝑎 be a closed ready tuple. If raw row 𝑖 is least with 𝗆𝖺𝗍𝖼𝗁𝖾𝗌(⃗𝑝𝑖,⃗𝑎,𝜃), then 𝑓†⃗𝑎⟶∗𝑒𝑖[𝜃𝑓][𝑓†/𝑓].
Referenced from 4 locations
Proof of Corollary 121.20 — Selected-clause composition
Proof. Theorem 121.19 gives the unique leaf, its closure 𝜉, and 𝜃 ≡𝜏ℓ𝜉. The leaf body is 𝑒𝑖[𝜏𝑓ℓ] by lemma 121.15, theorem 121.17. The closed-path computation of theorem 121.18 reduces to that body closed by the identity extension 𝜉𝑓, and then replaces 𝑓 by 𝑓†. Identity extensions compose: 𝜏𝑓ℓ𝜉𝑓≡(𝜏ℓ𝜉)𝑓≡𝜃𝑓. The closed leaf is therefore the displayed 𝑒𝑖[𝜃𝑓][𝑓†/𝑓]. ◻
★★☆ For 𝗈𝗇𝗅𝗒𝖭𝗂𝗅:∏𝐴:U𝑖∏𝑚:ℕ𝖵𝖾𝖼(𝐴,𝑚)→𝟏, compile the single row 𝗈𝗇𝗅𝗒𝖭𝗂𝗅(𝐴,.𝟢,𝗏𝗇𝗂𝗅) = ⋆. Give the uncovered symbolic pattern and state why, under the separate assumption that Timpl has no closed term of 𝟎, it yields no closed counterexample when 𝐴:=𝖨𝖽𝟐(𝗍𝗍,𝖿𝖿). Name the internal no-confusion map used in that argument. Then put 𝐴:=𝟏 and give a closed uncovered input. (A half page.)
Referenced from 3 locations
Generated equations
A leaf path records constructor choices and positive substitutions. Let ⃗𝑥 be the original frontier variables and ⃗𝑧 the variables of the residual frontier Θℓ. Compose the path substitutions to obtain 𝜌ℓ :Θℓ →Δ; each 𝑥𝑗[𝜌ℓ] is therefore a term in ⃗𝑧. Suppose the least row at the leaf is raw row 𝑖, whose written map and checked body are ̂𝜌𝑖 :Θ𝑖 →Δ and 𝑓 :𝐹Δ,Θ𝑖 ⊢𝑒𝑖 :𝐵[̂𝜌𝑖]. Lemma 121.15 supplies 𝜏ℓ :Θℓ →Θ𝑖, with ̂𝜌𝑖𝜏ℓ ≡𝜌ℓ. Compilation stores 𝑒𝑖[𝜏𝑓ℓ] in the leaf, and theorem 121.18 gives the leaf equation 𝑓†(⃗𝑥[𝜌ℓ])≡𝑒𝑖[𝜏𝑓ℓ][𝑓†/𝑓]. This is a judgmental equation because the eliminators and the generated identity transports compute on the constructor and reflexivity data of that path. The identity term 𝗋𝖾𝖿𝗅𝑓†(⃗𝑥[𝜌ℓ]):𝖨𝖽𝐵[𝜌ℓ](𝑓†(⃗𝑥[𝜌ℓ]),𝑒𝑖[𝜏𝑓ℓ][𝑓†/𝑓]) is the corresponding propositional equation theorem. It records the same fact but does not add a rule to judgmental equality.
An original row may produce several leaf equations, or none. The compiler emits only those judgmental leaf equations; it has no propositional-equation output. Reflexivity reifies any leaf equation as an identity theorem. For an overlapping later row, a theorem conditional on the proposition that no earlier row matches may instead be derived on demand by case analysis on the finite constructor frontier. That conditional theorem need not compute on a neutral input and is not promoted to a judgmental equation. The global equation asserted by a shadowed row is not generated at all.
For a successfully compiled Timpl-clauses matrix, the generated judgmental equations are exactly the leaf equations of its case tree. Each leaf equation belongs to the least source row matching its residual pattern. The compiler generates no propositional equations.
Referenced from 4 locations
Proof of Proposition 121.21 — Equation generation is exact
Proof. By the symbolic substitution dynamics of definition 78.18, a well-typed substitution for Θℓ follows its recorded constructor path to that leaf. Ordered specialization identifies its least surviving row. Lemma 121.15 constructs the typed map 𝜏ℓ, proves ̂𝜌𝑖𝜏ℓ ≡𝜌ℓ, and types the stored leaf body. The leaf computation of theorem 121.18 gives the displayed judgmental equation. No other equation is emitted by the construction of definition 121.9. Reflexivity inhabits the corresponding identity type by conversion; a conditional no-earlier-match theorem is a separate derived construction and is not a compiler output. ◻
★★☆ For the matrix 𝑔(𝗍𝗍,𝗍𝗍)=𝟢,𝑔(𝑥,𝖿𝖿)=𝗌𝗎𝖼(𝟢),𝑔(𝑥,𝑦)=𝗌𝗎𝖼(𝗌𝗎𝖼(𝟢)), construct the leftmost case tree. List its judgmental leaf equations. Give one valid propositional equation with an explicit no-earlier-match premise, and identify one unconditional source-row equation that is false. (A half page.)
Referenced from 3 locations
Closed-data simulation
For this theorem, fix the typed readiness judgment of definition 121.5 and the following closed, left-to-right dynamics. For a finite set 𝐻 of declared heads, evaluation contexts are E𝐻::=[]∣E𝐻𝑡∣𝑣E𝐻∣(E𝐻,𝑡)∣(𝑣,E𝐻)∣𝗉𝗋1(E𝐻)∣𝗉𝗋2(E𝐻)∣𝑐(⃗𝑞𝑐,E𝐻,⃗𝑡)∣𝖾𝗅𝗂𝗆𝐷(𝑃;⃗𝑚;E𝐻)∣ℎ⃗𝑞E𝐻⃗𝑡(ℎ∈𝐻). The function-side context E𝐻 𝑡 is available at every application node, including erased applications, so it can expose the leftmost head beta redex. Only the argument-side context 𝑣 E𝐻 is restricted to a supplied runtime argument; erased arguments are already ready and have no runtime child to evaluate. In the declared-head frame, ⃗𝑞 is the ready prefix and E𝐻 occupies the selected supplied runtime argument; ⃗𝑡 is the remaining supplied suffix and may be empty. Thus the frame includes a partially applied call while one of its supplied arguments evaluates and a saturated call before all of its runtime arguments are values. Erased arguments are closed normal forms and are skipped. The declared-head frame stops at the declared arity of ℎ; applications to a result of function type use the ordinary E𝐻 𝑡 frame. In the constructor frame, ⃗𝑞𝑐 is an admissible constructor prefix: every earlier runtime child is a value, while every earlier erased child is merely a closed well-typed term. The hole occupies the selected runtime child; there is no constructor frame whose hole is at an erased child. Thus 𝗏𝖼𝗈𝗇𝗌(𝑛 +𝑘,𝑎,E𝐻) is a valid frame after closed substitution even when the erased index 𝑛 +𝑘 is not normal. The eliminator form ranges exactly over the Boolean, natural-number, identity, and vector eliminators of the Timpl card, with the scrutinee in the displayed position; motives, types, and methods are not evaluated before a branch is selected. Writing 𝜖,𝜚 for the matching inherited Timpl application metadata, its beta root is (𝜆𝜖,𝜚𝑥.𝑒)𝜖,𝜚𝑎⇝0𝑇𝑒[𝑎/𝑥]. This root is available exactly when ⋅ ⊢𝑎 𝗋𝖾𝖺𝖽𝗒𝜚 :𝐴: a closed runtime value for 𝜚 =𝗋𝗎𝗇𝗍𝗂𝗆𝖾, and a closed normal form with no runtime child for 𝜚 =𝖾𝗋𝖺𝗌𝖾𝖽. The Timpl root relation otherwise consists of the two pair projections, the two Boolean computations, the zero and successor natural-number computations, identity elimination at reflexivity, and the 𝗏𝗇𝗂𝗅 and 𝗏𝖼𝗈𝗇𝗌 computations of vector elimination. These are precisely the computation rules already listed for the frozen kernel; there is no clause-tree root rule in the target.
The source root relation adds one rule. Let ⃗𝑎 be a closed ready tuple. If row 𝑖 is the least row with 𝗆𝖺𝗍𝖼𝗁𝖾𝗌(⃗𝑝𝑖,⃗𝑎,𝜃), then 𝑓⃗𝑎⇝0𝑀𝑒𝑖[𝜃𝑓], with recursive occurrences of 𝑓 unchanged. Define 𝑠 ⟶𝑀𝑡 when 𝑠 =E{𝑓}⟨𝑟⟩, 𝑡 =E{𝑓}⟨𝑟′⟩, and either 𝑟 ⇝0𝑀𝑟′ is this source root rule or 𝑟 ⇝0𝑇𝑟′ is one of the listed Timpl roots. Define 𝑠 ⟶𝑇𝑡 with E∅ and only Timpl roots. Write 𝑠 ⟶∗𝑡 for the reflexive–transitive closure of this ⟶𝑇 relation. The declared-head frame is therefore a source frame; it adds no target reduction rule. Write 𝗌𝗋𝖼(𝑀,⃗𝑎):=𝑓 ⃗𝑎 in the source language, and write 𝗌𝗋𝖼(𝑀,⃗𝑎) ⇓𝑤 for a finite ⟶𝑀-sequence to 𝑤, and 𝑓† ⃗𝑎 ⇓𝑤 for a finite ⟶𝑇-sequence. Both judgments concern closed data; they do not compare open neutral terms.
For a closed source expression 𝑠, let 𝗍𝗋𝑀(𝑠) be the capture-avoiding homomorphic translation that replaces every occurrence of the declared symbol 𝑓 by its compiled target 𝑓†. It fixes constructor symbols, maps source values to target values, and commutes with substitution. In particular, for every closed matching substitution 𝜃, 𝗍𝗋𝑀(𝑒𝑖[𝜃𝑓])≡𝑒𝑖[𝜃𝑓][𝑓†/𝑓]. The special declared-head frame does not translate literally to a target context: the lambda prefix of 𝑓† may contract before a source argument can take another step.
Define the administrative translation 𝖺𝗍𝗋𝑀(𝑠) by starting at 𝗍𝗋𝑀(𝑠) and repeatedly taking the unique deterministic target step only while that step is a beta contraction introduced by replacing a declared head 𝑓 with 𝑓†. Stop when the first nonadministrative step would be an argument evaluation or case-tree eliminator computation. The left-to-right context grammar makes this prefix unique. It is finite because each step consumes one of the finitely many argument binders on an active translated declared-head spine. Moreover, 𝗍𝗋𝑀(𝑠)⟶∗𝖺𝗍𝗋𝑀(𝑠). For a declared-head source frame, these contractions consume exactly the ready prefix ⃗𝑞. The residual target is a lambda value applied to the translation of the argument in the hole, so an ordinary target application context can perform that argument’s steps.
Let 𝑀 be a successfully compiled Timpl-clauses declaration with target 𝑓†. Let 𝑠 and 𝑠′ be closed source expressions. If 𝑠 ⟶𝑀𝑠′, then 𝖺𝗍𝗋𝑀(𝑠)⟶∗𝖺𝗍𝗋𝑀(𝑠′). If this step is the clause-root step selected by the least matching row 𝑖, with matching substitution 𝜃, then it specializes to 𝑓†⃗𝑎⟶∗𝑒𝑖[𝜃𝑓][𝑓†/𝑓]⟶∗𝖺𝗍𝗋𝑀(𝑒𝑖[𝜃𝑓]).
Referenced from 3 locations
Proof of Lemma 121.22 — One-step closed simulation after administrative beta reduction
Proof. First consider a root step. The definition of 𝖺𝗍𝗋𝑀 stops before a Timpl root. Homomorphic translation preserves that root, so one target step followed by the administrative prefix for 𝑠′ reaches 𝖺𝗍𝗋𝑀(𝑠′). For the added clause root, by theorem 121.19, the closed input follows the case-tree path to the same least row 𝑖. The factorization of lemma 121.15 identifies its closed leaf assignment with 𝜃. The composed root result corollary 121.20, using the independent lowering of theorem 121.18, therefore reaches exactly 𝑒𝑖[𝜃𝑓][𝑓†/𝑓]. Its administrative beta prefix reaches 𝖺𝗍𝗋𝑀(𝑒𝑖[𝜃𝑓]). The sequence to the row body can be empty only for a nullary declaration whose compiled target is already its sole row body.
For a source step inside an ordinary shared evaluation frame, structural induction on the frame lifts the finite root reduction through the corresponding target frame. In the source-only frame 𝑓 ⃗𝑞 E{𝑓} ⃗𝑡, administrative beta contraction consumes ⃗𝑞 and exposes a target lambda value immediately to the left of the translated hole. The ordinary target frame 𝑣 E∅ then lifts the induction hypothesis for the step in that hole; any newly enabled administrative contractions produce 𝖺𝗍𝗋𝑀(𝑠′). These cases exhaust the grammar of E{𝑓}. ◻
Let 𝑀 be a successfully compiled Timpl-clauses declaration with target 𝑓†. If 𝗌𝗋𝖼(𝑀,⃗𝑎) ⇓𝑤 for a closed argument tuple of the form just specified and a closed value 𝑤, then 𝑓†⃗𝑎⟶∗𝗍𝗋𝑀(𝑤). If 𝑤 contains no occurrence of the declared source symbol 𝑓, this is the target evaluation 𝑓† ⃗𝑎 ⇓𝑤. Let 𝑖 be the least source row matching ⃗𝑎, with matching substitution 𝜃. The initial source clause-root step is simulated by a finite sequence of compatible target steps to the body of that same least source row: 𝑓†⃗𝑎⟶∗𝑒𝑖[𝜃𝑓][𝑓†/𝑓].
Referenced from 5 locations
Proof of Theorem 121.23 — Target evaluation reproduces source evaluation
Proof. The displayed clause-root sequence is corollary 121.20; it composes theorem 121.19 with theorem 121.18, using lemma 121.15. For the evaluation claim, induct on the length of the given finite ⟶𝑀-sequence. At length zero the source term is already the value 𝑤. A value has no active evaluation position, so 𝖺𝗍𝗋𝑀(𝑤) =𝗍𝗋𝑀(𝑤). For a first step 𝑠 ⟶𝑀𝑠′, lemma 121.22 gives a finite target sequence from 𝖺𝗍𝗋𝑀(𝑠) to 𝖺𝗍𝗋𝑀(𝑠′). Concatenate it with the finite target sequence obtained from the induction hypothesis for the remaining source steps. Finally, 𝗍𝗋𝑀(𝗌𝗋𝖼(𝑀,⃗𝑎)) =𝑓† ⃗𝑎 reduces by its administrative prefix to 𝖺𝗍𝗋𝑀(𝗌𝗋𝖼(𝑀,⃗𝑎)), so the concatenated sequence has the required endpoints. Recursive calls need no separate premise: each is a later clause-root step in the finite source reduction and is covered by the same one-step lemma. ◻
The closed-data qualification is load bearing. At a neutral vector 𝑥𝑠, the vector eliminator in 𝖺𝗉𝗉𝖾𝗇𝖽†𝐴(𝑚,𝑛,𝑥𝑠,𝑦𝑠) is stuck, so neither append leaf equation applies. The theorem also says nothing about Agda’s complete clause language, Equations’ recursive programs, guards, coinduction, or arbitrary higher-order unification.
Impossible branches are certificates
An omitted branch and an absurd branch have different evidence. Omission is accepted only when constructor-index unification is negative. The explicit ! pattern asks the compiler to check the same fact and gives a location for its diagnostic.
The hand-compiled 𝗁𝖾𝖺𝖽 example and its forced dot already belong to construction 78.7; the general compiler reproduces that trace without adding a new admissibility argument. By contrast, the declaration with domain 𝑏 :𝟐, left side ℎ(!), and no right side is rejected. Both 𝗍𝗍 and 𝖿𝖿 are positive constructor branches, so neither can supply the negative certificate demanded by an absurd node.
Referenced from 2 locations
The identity-family boundary is inherited unchanged. Regard identity at a fixed left endpoint as the family 𝐷(𝑥):=𝖨𝖽𝐴(𝑎,𝑥). Splitting 𝑒 :𝐷(𝑎) against reflexivity generates the full constraint (𝑎;𝑒)≡𝑥:𝐴;𝐷(𝑥)(𝑎;𝗋𝖾𝖿𝗅𝑎). Its first component is the neutral index equation 𝑎 =𝑎. Restricted unification cannot delete that equation, so it never reaches a solution for the dependent element component and a K-shaped clause is rejected. This is different from a constructor equation such as 𝟢 =𝟢 :ℕ: the injectivity transition reduces the two equal nullary constructor heads to the empty argument telescope. Calling the identity branch absurd would not help, because reflexivity is compatible with the index even though the restricted run is stuck.
Source boundary. Maranget’s Warnings for Pattern Matching (2007) and Compiling Pattern Matching to Good Decision Trees (2008) own the nondependent specialization/default substrate and decision-tree heuristics summarized by definition 121.3, lemma 121.4 [Mar07, Mar08]; that work proves no typed dependent frontier result. Cockx and Abel, Elaborating Dependent (Co)pattern Matching: No Pattern Left Behind, JFP 30:e2 (2020), Contributions and Section 5.3, own the general core-language elaboration from dependent patterns and copatterns to typed case trees and its first-match correctness theorem [CA20]. The Timpl-clauses stage is strictly smaller: it has only the frozen Timpl families, first-order patterns, no copatterns, a fixed first-surviving-row and leftmost-blocker policy, explicit stuck diagnostics, and observations only at closed ready data. It additionally proves the written-row factorization needed by its early-body/late-obligation policy. Thus the theorem of theorem 121.19 is a new proof for this restricted card, not a transfer of the Cockx–Abel theorem. The exact checking-time delta was stated after definition 121.8.
The homogeneous constraints and restricted no-K unification used by the Timpl stages are the construction of Cockx, Devriese, and Piessens [CDP16], already developed at the indexed-family interface in section 78.4. Lieverse’s 2024 case-tree translation motivates the shape of the separate second stage of theorem 121.18, after a typed valid tree is already given [Lie24]. They are not no-K evidence: Lieverse’s unifier includes reflexive deletion, proves deletion and injectivity correctness using K, and omits the cycle transition retained by definition 78.9. The development also fixes its own universe of datatype descriptions. It therefore supports no claim about the restricted unifier, K-freedom, the Timpl-clauses stage, or every Agda declaration. Cockx–Abel’s historical account identifies the general second-stage lineage with the 2006 elimination construction of Goguen, McBride, and McKinna; this secondary attribution does not prove any theorem of this chapter. Cockx’s 2017 thesis supplies the later detailed account [CA20, Coc17]. Cockx’s dependent-programming course examples guide exercises but donate no compiler theorem. This chapter owns its smaller Timpl-clauses card, deterministic partial leftmost compiler, written-row factorization, and the composition corollary. No theorem about full Agda, Equations, Maranget’s optimizer, or Lieverse’s broader translation is transferred to Timpl-clauses.
Suggested first pass.
None of these problems is a prerequisite for a later chapter. Begin with exercise 121.6, exercise 121.7.
★★☆ For external universe-level parameters 𝑖,𝑗,𝑘, let 𝗓𝗂𝗉𝖶𝗂𝗍𝗁:{𝐴:U𝑖}→{𝐵:U𝑗}→{𝐶:U𝑘}→(𝐴→𝐵→𝐶)→∏𝑛:ℕ𝖵𝖾𝖼(𝐴,𝑛)→𝖵𝖾𝖼(𝐵,𝑛)→𝖵𝖾𝖼(𝐶,𝑛). Compile the two ordered clauses 𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝐴,𝐵,𝐶,𝑓,.𝟢,𝗏𝗇𝗂𝗅,𝗏𝗇𝗂𝗅)=𝗏𝗇𝗂𝗅,𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝐴,𝐵,𝐶,𝑓,.𝗌𝗎𝖼(𝑟),𝗏𝖼𝗈𝗇𝗌(𝑟,𝑎,𝑎𝑠),𝗏𝖼𝗈𝗇𝗌(.𝑟,𝑏,𝑏𝑠))=𝗏𝖼𝗈𝗇𝗌(𝑟,𝑓𝑎𝑏,𝗓𝗂𝗉𝖶𝗂𝗍𝗁(𝐴,𝐵,𝐶,𝑓,𝑟,𝑎𝑠,𝑏𝑠)). Each displayed row contains all seven telescope patterns: 𝐴,𝐵,𝐶,𝑓,𝑛, and the two vectors. Split the first vector and then the second. Trace both index constraints, identify every negative branch, give the typed case tree and its two leaf equations, and justify the recursive call using the designated first-vector child. (A page.)
Referenced from 4 locations
★★☆ Let 𝐴 :U𝑖, 𝑎 :𝐴, and 𝖪:∏𝑃:𝖨𝖽𝐴(𝑎,𝑎)→U𝑗𝑃(𝗋𝖾𝖿𝗅𝑎)→∏𝑒:𝖨𝖽𝐴(𝑎,𝑎)𝑃(𝑒). Attempt to compile the single clause 𝖪(𝑃,𝑝,𝗋𝖾𝖿𝗅𝑎)=𝑝. Write the generated homogeneous telescopic equality, expose its index and element components, and give the complete restricted-unifier run. Then attempt to replace the pattern by ! and identify the compatible constructor that invalidates the absurd assertion. (Half a page.)
Referenced from 4 locations
★★☆ For each of the following declarations, classify the first compiler result as success, uncovered constructor, stuck unification, stuck forced image, unforced inaccessible term, reachable absurd pattern, or erased-blocker relevance error: a complete Boolean negation; only the 𝗍𝗍 clause; the identity-family K clause; append with .𝑘 in place of .𝗌𝗎𝖼(𝑘); ℎ(!) at 𝟐; the single row 𝐸(𝗍𝗍) =𝟢 whose Boolean binder is declared erased; and the ordered rows 𝐹(𝑢,.𝑢,𝗋𝖾𝖿𝗅𝑢,𝗍𝗍)=𝟢,𝐹(𝑤,𝗍𝗍,𝑠,𝑧)=𝗌𝗎𝖼(𝟢) for 𝐹:∏𝑥:𝟐∏𝑎:𝟐𝖨𝖽𝟐(𝑎,𝑥)→𝟐→ℕ. Give the certificate, unsolved equation, or neutral forced image reported in every rejection. (A half page.)
Referenced from 3 locations
★★★ Practical project.dependent-clause-compiler Implement in Kappa the finite five-declaration decision model below. Give the model structured patterns, rows, and frontiers. Preserve row order, select the leftmost blocker, and execute all four selected-cell cases of definition 121.12. Process that cell once; a separate recursive matcher must consume any other substitution-eliminated cell without widening the frontier. Derive a generic split tree and its assignment lists from the specialization results, check every retained row’s width, and compute wildcard shadowing by ordered priority. Exercise the selected inaccessible-pattern case on an indexed successor with a nontrivial child: whole-term comparison must accept .𝗌𝗎𝖼(𝑘) and reject .𝗌𝗎𝖼(𝟢). This may be a hidden acceptance guard; the five public records remain the observable interface.
The exact records are: append-123 evaluates [1,2] +[3] =[1,2,3] by interpreting the derived tree; an independent append implementation does not satisfy the record. The overlap-bool record gives true 0, false 1, and a shadowed wildcard. The missing-false record reports path false; bad-dot prints forced suc(k) versus written k. The absurd-bool record names both reachable Boolean constructors. That finite aggregate is a stronger finite observation; the mathematical compiler returns the first 𝖻𝖺𝖽𝖠𝖻𝗌𝗎𝗋𝖽(𝑖,𝑐,𝜋) in declaration order. This is a finite acceptance slice, not evidence for arbitrary dependent frontiers, branch-local unification, or the general compiler theorems.
Referenced from 4 locations