One feature that appears quite straightforward to add to PCCθ islarge eliminations. For example, recall that system’s rule for pattern matching on pairs:
Γ`θ a : (Σx:A 1.A2)@θ0 Γ,x :A1,y :A2@θ0,z :hx,yi=a `θ b :B Γ`B :?σ Γ`θ pcase z a of hx,yi ⇒b :B EPCase
This rule appears only at the term level. However, it would be convenient to be allowed to pattern match at the type level as well. We could add a type form
pcasez a of hx,yi ⇒B and a corresponding inference rule: Γ`La : (Σx:A
1.A2)@θ0
Γ,x :A1,y :A2@θ0,z :hx,yi=a `B :k
Γ`k
Γ`pcasez a of hx,yi ⇒B :k TPCase
We require the scrutineea to check in the logical fragment to preserve normalization of the type level, but otherwise the rule closely resembles its term-level counterpart. This new type form is a large elimination because it eliminates a term at the type level. But the rule TConv is already a kind of large elimination—it eliminates equality proofs at the type level. The machinery that is needed in the normalization proof to deal with this is already included in our proofs (primarily the environmentρ which maps terms to values). Thus, we could interpret this new type form as follows, in the logical fragment:
Vθ πJpcasez a of hx,yi ⇒BK j ρ = ( Vθ πJBK j ρ[x7→v1][y7→v2][z7→refl] Ifρa ∗ hv 1,v2i ∅ otherwise
It seems likely that, with the interpretation shown here, not much would need to change in the existing normalization proof for PCCθ.
Chapter 7
Related work
Shuffled up Sixth Street in the rain.
Kept my head down as I looked past the people.
And in the department store, I found what I was looking for. This is the church, this is the crucible.
Wizard Buys a Hat
The Mountain Goats
This thesis attempts to solve two major problems with existing dependently typed languages. Unsurprisingly, both problems have been analyzed by other authors in the past. In this chapter, we examine some of the most closely related alternate approaches.
7.1
Other Approaches to Recursion and Partiality
Many authors have considered language features to model partiality and recursion in a consistent dependent type theory. Some of these techniques have even been implemented in existing dependently typed languages, with varying degrees of success.
7.1.1
Partiality Monad
Capretta proposed representing potentially non-terminating computations using a coinductive partiality monad [12]. This technique can be used in existing languages like Coq and Agda, which already support coinduction [20]. For example, Agda’s partiality monad has been used to present subtyping for recursive types [24] and represent potentially infinite parsing trees [23].
In both Coq and Agda, coinduction is supported via the addition of several prim- itive operators. The Agda standard library includes the following specification:
postulate
] : ∀ {a} {A : Set a}→ A→∞ A
[ : ∀ {a} {A : Set a}→∞A→ A
Here, Setis Agda’sTypeandais a universe level, similar to`in PCCθ. Intuitively, the ∞ type constructor creates a “suspended computation” of the appropriate type, while ] and [ are “delay” and “force” operators, respectively. For example, we may define infinite streams and a map function over them as follows:
data Stream (A : Set 0) : Set 0 where
Cons : A→∞(Stream A)→Stream A
map : {A B : Set 0}→(A→B)→Stream A→ Stream B
map f (Cons x xs) = Cons (f x) (] (map f ([ xs)))
There are several differences between this approach and the one outlined in this document. Coinduction is a very general method for representing infinite data, which we do not consider. On the other hand, corecursive definitions are required to be “productive”. For example, the following stream definition is rejected by Agda:
loop : {A : Set 0}→Stream A
loop = loop
Productivity is approximated by the “guard condition”, which requires every core- cursive call to be “guarded” by a coinductive constructor. Thus, while corecursion is excellent for modeling specific cases of non-termination (like streams), it is not well-suited for modeling functions whose termination behavior we simply do not yet understand, or functions that we wish to prove terminating extrinsically.
Additionally, the PCCθ approach has advantage that terminating and potentially partial functions are defined and reasoned about in the same way. As we can see above, working with coinduction in Agda requires the use of an alternate set of primitives, which demand their own operational semantics and require corresponding reasoning principles to be built into the language.
7.1.2
Non-Constructive Fixpoint semantics.
The work of Bertot and Komendantsky [8] describes a way to embed general recursive functions into Coq that does not use coinduction. They define a datatype partial A that is isomorphic to the usual Maybe A but is understood as representing a lifted CPO A⊥, and use classical logic axioms to provide a fixpoint combinator fixp. When
defining a recursive function the user must prove continuity side-conditions. Since recursive functions are defined nonconstructively they cannot be reduced directly, so instead one must reason about them using the fix-point equation.
7.1.3
Partial Types
Nuprl has at its core an untyped lambda calculus, capable of defining a general fixed point combinator for recursive computations. In the core type theory, all expressions
must be proven terminating when used. Constable and Smith [19] integrated po- tentially nonterminating computations through the addition of a type A of partial terms of type A. The fixpoint operator then has type (A → A) → A. However, to preserve the consistency of the logic, the type A must be restricted to admissible types. Crary [22] provides an expressive axiomatization of admissible types, but these conditions lead to significant proof obligations, especially when usingΣ-types.
Smith [53] provides an example which shows that Nuprl needs this restriction. Writinga↓for “aterminates”, define aΣ-type T of functions which are not total, and recursively define a pwhich inhabits T.
Total (f :N→N) def= (n :N)→(f n)↓
T def= Σ(f :N→N).Total f →False (p:T) def= fix (λp.hg, λh.—i)
g def= λx.if x= 0 then 0 else π1(p)(x−1)
Here the dash is an (elided) proof which sneakily derives a contradiction usingπ2(p)
and the hypothesis h that g is total. On the other hand, a separate induction shows that π1(p)is total; it returns 0 for all arguments. This is a contradiction.
PCCθ has almost all the ingredients for this paradox. Instead of a recursively defined pair we can use a recursive function Unit → T, and we can encode a↓ as Σ(y : A).a =y. What saves us is that the proof in the second component of p uses the following reasoning principle: if π1(p) terminates, then p terminates. In Nuprl
a↓ is a primitive predicate and this inversion principle is built in. But using our encoding, a function (π1(p) ↓) → (p ↓) would have to magically guess the second
component of a pair knowing only the first component. If we assume this function as an axiom we can encode the paradox and derive inconsistency, so our consistency proof for PCCθ shows that there is no way to write such a function.
7.1.4
Hoare Type Theory.
HTT [48, 56] is another embedding of general programs into a type theory like Coq. It goes beyond nontermination to also handle memory effects. Instead of a unary type constructor A, it adds the indexed type {P}x:A{Q} representing an effectful computation returning A and with pre- and postconditions P and Q. The assertions P and Q can use all of Coq, so the type of a computation can specify its behav- ior precisely. However, computations cannot be evaluated during typechecking (the fixpoint combinator and memory access primitives are implemented as Coq axioms with types but no reduction rules). Thus, as we observed with coinduction, poten- tially non-terminating expressions must be reasoned about with a whole new set of primitives.
7.1.5
Terminating Sublanguages
There are other dependently-typed languages which allow general recursion but iden- tify a sublanguage of terminating expressions. Aura [34] and F∗ [57] do this using the kind system: expressions whose type has kind Prop are checked for normaliza- tion. Types can contain values but not non-value expressions, so there is no way to write separate proofs about programs. There also is no facility to treat program- matic values as proofs, e.g. a logical case expression cannot destruct a value from the nonterminating fragment.
ATS [16], Guru [54], and Sep3 [35] are dependently-typed languages where the
logical and programmatic fragments are syntactically separate—in effect rejecting the rule TSub. One of the gains of this separation is that the logical language can be made CBN even though the programmatic one is CBV, avoiding the need for thunking. To do inductive reasoning, the Sep3 language adds an explicit “terminates” predicate.
Idris [11] is a full-spectrum dependently typed programming language that per- mits non-total definitions. Internally, it applies a syntactic test to check if function definitions are structurally decreasing, and programmers may ask whether particular definitions have been judged total. The typechecker will only reduce expressions that have been proved terminating, again precluding separate equational reasoning about partial programs. Idris’ metatheory has not been studied formally.
7.1.6
The “Later” Modality
Nakano [47] introduced the “later” modality to define a total language with guarded recursive types. Intuitively, a term of type•A(pronounced “laterA”) will be usable as a term of typeAin the future. The recursive type µx.Athen unfolds to[•µx.A/x]A rather than [µx.A/x]A. Using this modality, he is able to give the type (•A → A) → A to the Y combinator. This type allows programmers to define a variety of recursive functions while still ensuring that the language is normalizing. Nakano uses a step-indexed realizability interpretation to prove the normalization property for his language, suggesting deep connections with the present work.
The later modality has been used by subsequent authors to design languages for a variety of purposes. Krishnaswami and Benton use it define a total language for functional reactive programming [37, 36]. Birkedal et al. [9] study the topos of trees, which they observe can model an extension of Nakano’s calculus to a full dependent type theory with guarded recursion. While these authors do not consider languages with partiality and their settings have substantial differences from our own, their success in extending step-indexing and closely related techniques to model recursion in larger languages demonstrates the versatility of the technique.