1. Introduction
In dependent type theory, terms are type-checked modulo definitional equality, a congruence generated by
$\alpha$
-,
$\beta$
-, and
$\eta$
-laws, as well as unfolding of definitions. Unfolding definitions is to some extent a convenience that allows type checkers to silently discharge many proof obligations, for example, a list of length
$1+1$
is without further annotation also a list of length
$2$
. It is by no means the case, however, that we always want a given definition to unfold:
-
• Modularity: Dependent types are famously sensitive to the smallest changes to definitions, such as whether
$(\!+\!)$
recurs on its first or its second argument. If we plan to change a definition in the future, it may be desirable to avoid exposing its implementation to the type checker. -
• Usability: While unfolding may simplify proof states, it also has the potential to complicate them, resulting in unreadable subgoals, error messages, etc. A user may find that certain definitions are likely to be problematic in this way and thus opt not to unfold them.
Many proof assistants accordingly have implementation-level support for marking definitions opaque (unable to be unfolded), including Agda’s abstract (The Agda Team 2021) and Coq’s Qed (The Coq Development Team 2022). But unfolding definitions is not merely a matter of convenience: to reason about a function, we must unfold it. For example, if we make the definition of
$(\!+\!)$
opaque, then
$(\!+\!)$
is indistinguishable from a variable of type
$\mathbb{N}\to \mathbb{N}\to \mathbb{N}$
and so cannot be shown to be commutative, satisfy
$1+1=2$
, etc.
In practice, proof assistants resolve this contradiction by adopting an intermediate stance: definitions are transparent (unfolded during type checking) by default, but users are given some control over their unfolding. Coq provides conversion tactics (cbv, simpl, etc.) for applying definitional equalities, each of which accepts a list of definitions to unfold; its Opaque and Transparent commands toggle the default unfolding behavior of a transparent definition; and the SSReflect tactic language natively supports a “locking” idiom for controlling when definitions unfold (Gonthier et al. Reference Gonthier, Mahboubi and Tassi2016). Agda allows users to group multiple definitions into a single abstract block, inside of which those definitions are transparent and outside of which they are opaque; this allows users to define a function, prove all lemmas that depend on the function’s definition, and then irreversibly make the function and lemmas opaque.
These mechanisms for controlling unfolding pose interesting trade-offs for users: which definitions should be transparent, and which should be opaque? Transparency is in some cases necessary and in many cases convenient, but it is problematic both from an engineering perspective – because any edit to a transparent definition can break the well-typedness of any number of its use sites – and from a performance perspective – because checking definitional equality of type indices often requires unfolding nested definitions into large normal forms.
In addition, the behavior of these mechanisms is more subtle than it may at first appear. In Agda, definitions within abstract blocks are transparent to other definitions in the same block, but opaque to the types of those definitions; without such a stipulation, those types may cease to be well-formed when the earlier definition is made opaque. Furthermore, abstract blocks are anti-modular, requiring users to anticipate all future lemmas about definitions in a block.Footnote 1 Coq’s conversion tactics are more flexible than Agda’s abstract blocks, but being tactics, their behavior can be harder to predict. The lock idiom in SSReflect is more predictable because it creates opaque definitions but comes in four different variations to simplify its use in practice.
1.1 Contributions
We propose a mechanism for fine-grained control over the unfolding of definitions in dependent type theory. We introduce language-level primitives for controlled unfolding that are elaborated into a core calculus with extension types, a connective first introduced by Riehl and Shulman (Reference Riehl and Shulman2017). We justify our elaboration algorithm by establishing a normalization theorem (and hence the decidability of type checking and injectivity of type constructors) for our core calculus, and we have implemented our system for controlled unfolding in the experimental
proof assistant (RedPRL Development Team 2020).
Definitions in our framework are opaque by default but can be selectively and locally unfolded as if they were transparent. Our system is finer-grained and more modular than Agda’s abstract blocks: we need not collect all lemmas that unfold a given definition into a single block, making our mechanism better suited to libraries. Our primitives have more predictable meaning and performance than Coq’s unfolding tacticsFootnote 2 because they are implemented by straightforward elaboration into a core Martin-Löf type theory (MLTT) extended with new types and declaration forms.
In particular, we refine earlier approaches to representing definitions within type theory (Dreyer et al. Reference Dreyer, Crary and Harper2003; Harper & Stone Reference Harper, Stone, Plotkin, Stirling and Tofte2000; Milner et al. Reference Milner, Tofte, Harper and MacQueen1997; Sterling and Harper Reference Sterling and Harper2021) in order to more faithfully represent definitions as they are actually used in practice: as neither fully opaque or transparent but instead a mix of the two. Drawing inspiration from cubical type theory (Angiuli et al. Reference Angiuli, Hou (Favonia), Harper, Ghica and Jung2018, Reference Angiuli, Brunerie, Coquand, Hou (Favonia), Harper and Licata2021; Cohen et al. Reference Cohen, Coquand, Huber and Mörtberg2017), we extend MLTT with proof-irrelevant proposition symbols
$p$
, dependent products
$\{p\}\,A$
over those propositions, and extension types
$\lbrace A\vert p \hookrightarrow a \rbrace$
, the subtype of
$A$
consisting of the elements of
$A$
that definitionally equal
$a$
under the assumption that
$p$
is true. For readers familiar with cubical type theory, extension types are similar to path types
$(\mathsf{Path}\,A\,a_0\,a_1)$
, which classify functions out of an abstract interval
$\mathbb{I}$
that are definitionally equal to
$a_0$
and
$a_1$
when evaluated at the interval’s endpoints
$0,1:\mathbb{I}$
.
Encoding definitions through particular types confers a number of benefits. For instance, our mechanism for definitions and unfolding are automatically invariant under definitional equivalence: replacing one term by a definitionally equal alternative cannot change the unfolding behavior of a program. Furthermore, using extension types to encode definitions ensures that our elaboration algorithm is extremely modular and predictable: the rules for extension types are simple and, once grasped, it becomes easy to predict the interactions between unfolding definitions and other features within the language. This elaboration algorithm then serves as a reference for the behavior of our mechanism, against which other implementation strategies may be checked.
Like many elaboration algorithms for dependent type theory, executing our elaboration algorithm requires deciding the equality of types in the core language. To show that our elaboration algorithm can be implemented, we prove a normalization theorem for our core calculus, characterizing its definitional equivalence classes of types and terms and as a corollary establishing the decidability of type checking. This is more subtle than it may appear: the heart of our normalization proof amounts to correctly tracking when definitions are allowed to unfold as well as when they should remain opaque. In the face of higher-order programs and dependent types, this is quite difficult.
Another benefit to shifting from opaque definitions to extension types is their well-studied metatheory. Specifically, we are able to adapt and extend Sterling’s technique of synthetic Tait computability (STC) (Sterling Reference Sterling2021; Sterling and Angiuli Reference Sterling and Angiuli2021; Sterling and Harper Reference Sterling and Harper2021) to prove normalization for our core language. Our proof is fully constructive, an improvement on the prior work of Sterling and Angiuli (Reference Sterling and Angiuli2021); we have also corrected an error in the handling of universes in an earlier revision of Sterling’s doctoral dissertation (Sterling Reference Sterling2021) that was detected while preparing this paper.
1.2 Outline
In Section 2, we introduce our controlled unfolding primitives by way of examples, and in Section 3 we walk through how these examples are elaborated into our core language of type theory with proposition symbols and extension types. In Section 4, we present our elaboration algorithm, and in Section 5 we discuss our implementation of the above in the
proof assistant. In Section 6, we establish normalization and its corollaries for our core calculus. We conclude with a discussion of related work in Section 7.
2. A Surface Language with Controlled Unfolding
We begin by describing an Agda-like surface language for a dependent type theory with controlled unfolding. In Section 4, we will give precise meaning to this language by explaining how to elaborate it into our core calculus; for now, we proceed by example, introducing our new primitives bit by bit. Our examples will concern the inductively defined natural numbers and their addition function:
\begin{align*} \begin{array}{l} (\mathsf{+}) : \mathbb{N}\to \mathbb{N}\to \mathbb{N}\\ \mathsf{ze} + n = n\\ {\mathsf{su}\,m} + n = \mathsf{su}\,(m + n) \end{array} \end{align*}
2.1 A simple dependency: length-indexed vectors
In our language, definitions such as
$(\!+\!)$
are opaque by default – they are not unfolded automatically. To illustrate the need to selectively unfold
$(\!+\!)$
, consider the indexed inductive type of length-indexed vectors with the following constructors:
\begin{align*} \begin{array}{l} {[\hspace {0.1pt}]}{} : \mathsf{vec}\,\mathsf{ze}\,A\\ (\!\mathbin {::}\!) : A\to \mathsf{vec}\,n\,A\to \mathsf{vec}\,(\mathsf{su}\,n)\,A \end{array} \end{align*}
Suppose we attempt to define the append operation on vectors by dependent pattern matching on the first vector. Our goals would be as follows:

As it stands, the goals above are in normal form and cannot be proved; however, we may indicate that the definition of
$(\!+\!)$
should be unfolded within the definition of
$(\!\oplus\!)$
by adding the following top-level
$\mathbf{unfolds}$
annotation:
![]()
With our new declaration, the goals simplify:

The first goal is solved with
$v$
itself; for the second goal, we begin by applying the
$\mathsf{vcons}$
constructor:

The remaining goal is just our induction hypothesis
$u\oplus v$
. All in all, we have:
\begin{align*} \begin{array}{l} (\!\oplus\!)\,{\mathbf{unfolds}}\,(\!+\!)\\(\!\oplus\!) : \mathsf{vec}\,m\,A\to \mathsf{vec}\,n\,A\to \mathsf{vec}\,(m+n)\,A\\ {[\hspace {0.1pt}]}{} \oplus v = v\\ (a \mathbin {::}{} u) \oplus v = a \mathbin {::}{} (u\oplus v) \end{array} \end{align*}
2.2 Transitive unfolding
Now suppose we want to prove that
$\mathsf{map}$
distributes over
$(\!\oplus\!)$
. In doing so, we will certainly need to unfold
$\mathsf{map}$
, but it turns out this will not be enough:
\begin{align*} \begin{array}{l} \mathsf{map} : (A\to B) \to \mathsf{vec}\,n\,A \to \mathsf{vec}\,n\,B\\ \mathsf{map}\,f\,{[\hspace {0.1pt}]}{} = {[\hspace {0.1pt}]}{}\\ \mathsf{map}\,f\,(a \mathbin {::}{} u) = f\,a \mathbin {::}{} \mathsf{map}\,f\,u \end{array} \end{align*}

To make further progress, we must also unfold
$(\!\oplus\!)$
:

In our language, unfolding
$(\!\oplus\!)$
has the side effect of also unfolding
$(\!+\!)$
: in other words, unfolding is transitive. To see why this is the case, observe that the unfolding of
$(a \mathbin {::}{} u) \oplus v : \mathsf{vec}\,({\mathsf{su}\,m} + n)\,A$
, namely
$a \mathbin {::}{} (u\oplus v) : \mathsf{vec}\,(\mathsf{su}\,(m + n))\,A$
, would otherwise not be well-typed. From an implementation perspective, one can think of the transitivity of unfolding as necessary for subject reduction. Having unfolded
$\mathsf{map}$
,
$(\!\oplus\!)$
, and thus
$(\!+\!)$
, we complete our definition:
\begin{align*} \begin{array}{l} \mathsf{cong} : (f:A\to B)\to a\equiv a^{\prime }\to f\,a\equiv f\,a^{\prime }\\ \mathsf{cong}\,f\,\mathsf{refl} = \mathsf{refl} \end{array} \end{align*}
\begin{align*} \begin{array}{l} \mathsf{map\text{-}{\oplus }}\,{\mathbf{unfolds}}\,\mathsf{map}; (\!\oplus\!)\\ \mathsf{map\text{-}{\oplus }} : (f:A\to B)\,(u:\mathsf{vec}\,m\,A)\,(v:\mathsf{vec}\,n\,A) \to \mathsf{map}\,f\,(u\oplus v) \equiv \mathsf{map}\,f\,u \oplus \mathsf{map}\,f\,v\\ \mathsf{map\text{-}{\oplus }}\,f\,{[\hspace {0.1pt}]}{}\,v = \mathsf{refl}\\ \mathsf{map\text{-}{\oplus }}\,f\,(a \mathbin {::}{} u)\,v = \mathsf{cong}\,(f\,a \mathbin {::}{})\,(\mathsf{map\text{-}{\oplus }}\,f\,u\,v) \end{array} \end{align*}
2.3 Recovering unconditionally transparent/opaque definitions
There are also times when we intend a given definition to be a fully transparent abbreviation, in the sense of being unfolded automatically whenever possible. We indicate this with an
$\mathbf{abbreviation}$
declaration:

Then the following lemma can be defined without any explicit unfolding:
\begin{align*} \begin{array}{l} \mathsf{abbrv\text{-}{}example} : \mathsf{singleton}\,5 \equiv (5 \mathbin {::}{} {[\hspace {0.1pt}]}{})\\ \mathsf{abbrv\text{-}{}example} = \mathsf{refl} \end{array} \end{align*}
The meaning of the
$\mathbf{abbreviation}$
keyword must account for unfolding constraints. For instance, what would it mean to make
$\mathsf{map\text{-}{\oplus }}$
an abbreviation?
\begin{align*} \begin{array}{l} {\mathbf{abbreviation}}\,\mathsf{map\text{-}{\oplus }}\\ \mathsf{map\text{-}{\oplus }}\,{\mathbf{unfolds}}\,\mathsf{map};\; (\!\oplus\!)\\ \dots \end{array} \end{align*}
We cannot unfold
$\mathsf{map\text{-}{\oplus }}$
in all contexts, because its definition is only well-typed when
$\mathsf{map}$
and
$(\!\oplus\!)$
are unfolded. The meaning of this declaration must, therefore, be that
$\mathsf{map\text{-}{\oplus }}$
shall be unfolded just as soon as
$\mathsf{map}$
and
$(\!\oplus\!)$
are unfolded. In other words,
${\mathbf{abbreviation}}\,\vartheta$
followed by
$\vartheta \,{\mathbf{unfolds}}\,\kappa _1;\ldots ;\;\kappa _n$
means that unfolding
$\vartheta$
is synonymous with unfolding all of
$\kappa _1;\ldots ;\;\kappa _n$
.
Conversely, we may intend a given definition never to unfold, which we may indicate by a corresponding
$\mathbf{abstract}$
declaration. Because definitions in our system do not automatically unfold, the force of
${\mathbf{abstract}}\,\vartheta$
is simply to prohibit users from including
$\vartheta$
in any subsequent
$\mathbf{unfolds}$
annotations.
2.4 Unfolding within the type
The effect of a
$\vartheta \,{\mathbf{unfolds}}\,\kappa _1;\ldots ;\;\kappa _n$
declaration is to make
$\kappa _1;\ldots \kappa _n$
unfold within the definition of
$\vartheta$
, but still not within its type; it will happen, however, that a type might not be expressible without some unfolding. First, we will show how to accommodate this situation using only features we have introduced so far, and then in Section 2.5, we will devise a more general and ergonomic solution.
Consider the left-unit law for
$(\!\oplus\!)$
: in order to state that a vector
$u$
is equal to the vector
${[\hspace {0.1pt}]}{}\oplus u$
, we must contend with their differing types
$\mathsf{vec}\,n\,A$
and
$\mathsf{vec}\,(\mathsf{ze}+n)\,A$
, respectively. One approach is to rewrite along the left-unit law for
$\mathbb{N}$
; indeed, to state the right-unit law for
$(\!\oplus\!)$
, one must rewrite along the right-unit law for
$\mathbb{N}$
. But here, because
$(\!+\!)$
computes on its first argument,
$\mathsf{vec}\,n\,A$
and
$\mathsf{vec}\,(\mathsf{ze}+n)\,A$
would be definitionally equal types if we could unfold
$(\!+\!)$
.
In order to formulate the left-unit law for
$(\!\oplus\!)$
, we start by defining its type as an abbreviation that unfolds
$(\!+\!)$
:
\begin{align*} \begin{array}{l} {\mathbf{abbreviation}}\,\oplus \mathsf {\text{-}left\text{-}unit\text{-}type}\\ \oplus \mathsf {\text{-}left\text{-}unit\text{-}type}\,{\mathbf{unfolds}}\,(\!+\!)\\ \oplus \mathsf {\text{-}left\text{-}unit\text{-}type} : \mathsf{vec}\,n\,A\to \mathsf{Type}\\ \oplus \mathsf {\text{-}left\text{-}unit\text{-}type}\,u = {[\hspace {0.1pt}]}{}\oplus u \equiv u \end{array} \end{align*}
Now we may state the intended lemma using the type defined above:

Clearly, we must unfold
$(\!+\!)$
and thus
$\oplus \mathsf {\text{-}left\text{-}unit\text{-}type}$
to simplify our goal:

We complete the proof by unfolding
$(\!\oplus\!)$
itself, which transitively unfolds
$(\!+\!)$
:
\begin{align*} \begin{array}{l} \oplus \mathsf {\text{-}left\text{-}unit}\,{\mathbf{unfolds}}\,(\!\oplus\!)\\ \oplus \mathsf {\text{-}left\text{-}unit} : (u : \mathsf{vec}\,n\,A) \to \oplus \mathsf {\text{-}left\text{-}unit\text{-}type}\,u\\ \oplus \mathsf {\text{-}left\text{-}unit}\,u = \mathsf{refl} \end{array} \end{align*}
2.5 Unfolding within subexpressions
We have just demonstrated how to unfold definitions within the type of a declaration by defining that type as an additional declaration; using the same technique, we can introduce unfoldings within any subexpression by hoisting that subexpression to a top-level definition with its own unfolding constraint.
Unfolding within the type, revisited. Rather than repeating the somewhat verbose pattern of Section 2.4, we abstract it as a new language feature that is easily eliminated by elaboration. In particular, we introduce a new expression former
${\mathbf{unfold}}\,\kappa \,{\mathbf{in}}\,M$
that can be placed in any expression context. Let us replay the example from Section 2.4, but using
$\mathbf{unfold}$
rather than an auxiliary definition:

The type
${\mathbf{unfold}}\,(\!+\!)\,{\mathbf{in}}\,\quad\oplus u \equiv u$
is in normal form; the only way to simplify it is to unfold
$(\!+\!)$
. We could do this with another inline
$\mathbf{unfold}$
expression (see
$\oplus \mathsf {\text{-}left\text{-}unit'}$
below), but here we will use a top-level declaration:

By virtue of the above, the
$\mathbf{unfold}$
expression in our hole has computed away and we are left with
as
$(\!\oplus\!)$
is still abstract in this scope. To make progress, we strengthen the declaration to unfold
$(\!\oplus\!)$
in addition to
$(\!+\!)$
:

The meaning of the code above is exactly as described in Section 2.4: the
$\mathbf{unfold}$
scope is elaborated to a new top-level
$\mathbf{abbreviation}$
that unfolds
$(\!+\!)$
.
Expression-level vs. top-level unfolding. We noted in our definition of
$\oplus \mathsf {\text{-}left\text{-}unit}$
above that we could have replaced the top-level
${\mathbf{unfolds}}\,(\!\oplus\!)$
directive of
$\oplus \mathsf {\text{-}left\text{-}unit}$
with the new expression-level
${\mathbf{unfold}}\,(\!\oplus\!)\,{\mathbf{in}}$
as follows:
\begin{align*} \begin{array}{l} \oplus \mathsf {\text{-}left\text{-}unit'} : (u : \mathsf{vec}\,n\,A) \to {\mathbf{unfold}}\,(\!+\!)\,{\mathbf{in}}\,{[\hspace {0.1pt}]}{}\oplus u\equiv u\\ \oplus \mathsf {\text{-}left\text{-}unit'}\,u = {\mathbf{unfold}}\,(\!\oplus\!)\,{\mathbf{in}}\,\mathsf{refl} \end{array} \end{align*}
The resulting definition of
$\oplus \mathsf {\text{-}left\text{-}unit'}$
has slightly different behavior than
$\oplus \mathsf {\text{-}left\text{-}unit}$
above: whereas unfolding
$\oplus \mathsf {\text{-}left\text{-}unit}$
causes
$(\!\oplus\!)$
to unfold transitively, we can unfold
$\oplus \mathsf {\text{-}left\text{-}unit'}$
without unfolding
$(\!\oplus\!)$
– at the cost of
${\mathbf{unfold}}\,(\!\oplus\!)$
expressions appearing in our goal. This more granular behavior may be desirable in some cases, and it is a strength of our language and its elaborative semantics that the programmer can manipulate unfolding in such a fine-grained manner.
For completeness, we show the elaborated version of
$\oplus \mathsf {\text{-}left\text{-}unit'}$
resulting from eliminating expression-level unfolding from the definition. We defer a systematic discussion of this transformation till Section 4.
\begin{align*} \begin{array}{l} {\mathbf{abbreviation}}\,\oplus\mathsf{\text{-}left\text{-}unit'\text{-}type}\\ \oplus \mathsf {\text{-}left\text{-}unit'\text{-}type}\,{\mathbf{unfolds}}\,(\!+\!)\\ \oplus \mathsf {\text{-}left\text{-}unit'\text{-}type} : \mathsf{vec}\,n\,A\to \mathsf{Type}\\ \oplus \mathsf {\text{-}left\text{-}unit'\text{-}type}\,u = {[\hspace {0.1pt}]}{}\oplus u \equiv u \end{array} \end{align*}
\begin{align*} \begin{array}{l} {\mathbf{abbreviation}}\,\oplus \mathsf {\text{-}left\text{-}unit'\text{-}body}\\ \oplus \mathsf {\text{-}left\text{-}unit'\text{-}body}\,{\mathbf{unfolds}}\,(\!\oplus\!)\\ \oplus \mathsf {\text{-}left\text{-}unit'\text{-}body} : (u : \mathsf{vec}\,n\,A)\to \oplus \mathsf {\text{-}left\text{-}unit'\text{-}type}\,u\\ \oplus \mathsf {\text{-}left\text{-}unit'\text{-}body}\,u = \mathsf{refl} \end{array} \end{align*}
\begin{align*} \begin{array}{l} \oplus \mathsf {\text{-}left\text{-}unit'} : (u : \mathsf{vec}\,n\,A)\to \oplus \mathsf {\text{-}left\text{-}unit'\text{-}type}\,u\\ \oplus \mathsf {\text{-}left\text{-}unit'}\,u = \oplus \mathsf {\text{-}left\text{-}unit'\text{-}body}\,u \end{array} \end{align*}
In our experience, expression-level unfolding seems more commonly useful for end users than top-level unfolding; on the other hand, the clearest semantics for expression-level unfolding are stated in terms of top-level unfolding. Because one of our goals is to provide an account of unfolding that admits a reliable and precise mental model for programmers, it is desirable to include both top-level and expression-level unfolding in the surface language.
3. Controlling Unfolding with Extension Types
Having introduced our new surface language constructs for controlled unfolding in Section 2, we now describe how to elaborate these constructs into our dependently typed core calculus. Again we proceed by example, deferring our formal descriptions of the elaboration algorithm to Section 4.
3.1 A core calculus with proposition symbols
Our core calculus parameterizes intensional MLTT (Martin-Löf Reference Martin-Löf, Rose and Shepherdson1975) by a bounded meet semilattice of proposition symbols
$p\in \mathbb{P}$
and adjoins to the type theory a new form of context extension and two new type formers
$\{p\}\, A$
and
$\lbrace A\vert p \hookrightarrow M \rbrace$
involving proposition symbols:
![]()
The bounded meet semilattice structure on
$\mathbb{P}$
closes proposition symbols under conjunction
$\land$
and the true proposition
$\top$
, thereby partially ordering
$\mathbb{P}$
by entailment
$p \leq q$
(“
$p$
entails
$q$
”) satisfying the usual principles of propositional logic. We say
$p$
is true if
$\top$
entails
$p$
; the context extension
$\Gamma ,p$
hypothesizes that
$p$
is true.
The type
$\{p\}\, A$
is the dependent product “
$\{\_ : p\}\to A$
,” that is,
$\{p\}\, A$
is well-formed when
$A$
is a type under the hypothesis that
$p$
is true, and
$f : \{p\}\, A$
when, given that
$p$
is true, we may conclude
$f : A$
. The extension type
$\lbrace A\vert p \hookrightarrow a_p\rbrace$
is well-formed when
$A$
is a type and
$a_p : \{p\}\, A$
; its elements
$a : \lbrace A\vert p \hookrightarrow a_p\rbrace$
are terms
$a : A$
satisfying the side condition that when
$p$
is true, we have
$a = a_p : A$
. We provide inference rules for the core calculus, including these connectives, in Section 4.1.
3.2 Elaborating controlled unfolding to our core calculus
Our surface language extends a generic surface language for dependent type theory with a new expression former
$\mathbf{unfold}$
and several new declaration forms:
$\vartheta \,{\mathbf{unfolds}}\,\kappa _1;\dots ;\;\kappa _n$
for controlled unfolding,
${\mathbf{abbreviation}}\,\vartheta$
for transparent definitions, and
${\mathbf{abstract}}\,\vartheta$
for opaque definitions. Elaboration transforms these surface-language declarations into core-language signatures, that is, sequences of declarations over our core calculus of MLTT with proposition symbols.
Our signatures include the following declaration forms:
We now revisit our examples from Section 2, illustrating how they are elaborated into our core calculus:
Plain definitions
Recall our unadorned definition of
$(\!+\!)$
from Section 2:
\begin{align*} \begin{array}{l} (\!+\!) : \mathbb{N}\to \mathbb{N}\to \mathbb{N}\\ \mathsf{ze} + n = n\\ {\mathsf{su}\,m} + n = \mathsf{su}\,(m + n) \end{array} \end{align*}
We elaborate
$(\!+\!)$
into a sequence of declarations: first, we introduce a new proposition symbol
$\Upsilon _{+}$
corresponding to the proposition that “
$(\!+\!)$
unfolds.” Next, we introduce a new definition
$\delta _{+}:\mathbb{N}\to \mathbb{N}\to \mathbb{N}$
satisfying the defining clauses of
$(\!+\!)$
above, under the (trivial) assumption of
$\top$
; finally, we introduce a new constant
$(\!+\!)$
involving the extension type of
$\delta _{+}$
along
$\Upsilon _{+}$
:
\begin{align*} \begin{array}{l} {\mathbf{prop}}\,\Upsilon _{+}\leq \top \\ \\[-8pt] \delta _{+} : \{\top \}\,(m\,n : \mathbb{N})\to \mathbb{N}\\ \delta _{+}\,\mathsf{ze}\,n = n\\ \delta _{+}\,(\mathsf{su}\,m)\,n = \mathsf{su}\,(\delta _{+}\,m\,n)\\ \\[-8pt] {\mathbf{const}}\,(\!+\!) : \lbrace \mathbb{N}\to \mathbb{N}\to \mathbb{N} \vert \Upsilon _{+} \hookrightarrow \delta _{+}\rbrace \end{array} \end{align*}
Top-level unfolding
To understand why we have elaborated
$(\!+\!)$
in this way, let us examine how to elaborate top-level unfolding declarations (Section 2.1):
\begin{align*} \begin{array}{l} (\!\oplus\!)\,{\mathbf{unfolds}}\,(\!+\!)\\ (\!\oplus\!) : \mathsf{vec}\,m\,A\to \mathsf{vec}\,n\,A\to \mathsf{vec}\,(m+n)\,A\\ {[\hspace {0.1pt}]}{} \oplus v = v\\ (a \mathbin {::}{} u) \oplus v = a \mathbin {::}{} (u\oplus v) \end{array} \end{align*}
To elaborate
$(\!\oplus\!)\,{\mathbf{unfolds}}\,(\!+\!)$
, we define the proposition symbol
$\Upsilon _{\oplus }$
to entail
$\Upsilon _{+}$
, capturing the idea that unfolding
$(\!\oplus\!)$
always causes
$(\!+\!)$
to unfold; in order to cause
$(\!+\!)$
to unfold in the body of
$(\!\oplus\!)$
, we assume
$\Upsilon _{+}$
in the definition of
$\delta _{\oplus }$
. In full, we elaborate the definition of
$(\!\oplus\!)$
as follows:
\begin{align*} \begin{array}{l} {\mathbf{prop}}\,\Upsilon _{\oplus }\leq \Upsilon _{+}\\ \\[-5pt] \delta _{\oplus } : \{\Upsilon _{+}\} \, (u:\mathsf{vec}\,m\,A)\,(v:\mathsf{vec}\,n\,A)\to \mathsf{vec}\,(m+n)\,A\\ \delta _{\oplus }\,{[\hspace {0.1pt}]}{}\,v = v\\ \delta _{\oplus }\,(a \mathbin {::}{} u)\,v = a \mathbin {::}{} (\delta _{\oplus }\,u\,v)\\ \\[-5pt] {\mathbf{const}}\,(\!\oplus\!) : \lbrace \mathsf{vec}\,m\,A\to \mathsf{vec}\,n\,A\to \mathsf{vec}\,(m+n)\,A \vert \Upsilon _{\oplus } \hookrightarrow \delta _{\oplus }\rbrace \end{array} \end{align*}
Observe that the definition of
$\delta _{\oplus }$
is well-typed because
$\Upsilon _{+}$
is true in its scope: thus, the extension type of
$(\!+\!)$
causes
$\mathsf{ze}+n$
to be definitionally equal to
$\delta _{+}\,\mathsf{ze}\,n$
, which in turn is defined to be
$n$
. The constraint
$\Upsilon _{\oplus }\hookrightarrow \delta _{\oplus }$
is well-typed because
$\Upsilon _{\oplus }$
entails
$\Upsilon _{+}$
.
If a definition
$\vartheta$
unfolds multiple definitions
$\kappa _1;\dots ;\;\kappa _n$
, we define
$\Upsilon _{\vartheta }$
to entail (and define
$\delta _{\vartheta }$
to assume) the conjunction
$\Upsilon _{\kappa _1}\land \dots \land \Upsilon _{\kappa _n}$
; if a definition
$\vartheta$
unfolds no definitions, then
$\Upsilon _{\vartheta }$
entails (and
$\delta _{\vartheta }$
assumes)
$\top$
, as in our
$(\!+\!)$
example.
Abbreviations
To elaborate the combination of the declarations
${\mathbf{abbreviation}}\,\vartheta$
and
$\vartheta \,{\mathbf{unfolds}}\,\kappa _1;\dots ;\;\kappa _n$
, we define
$\Upsilon _{\vartheta }$
to equal the conjunction
$\Upsilon _{\kappa _1}\land \dots \land \Upsilon _{\kappa _n}$
. For example, consider the following code from Section 2.3:
\begin{align*} \begin{array}{l} {\mathbf{abbreviation}}\,\mathsf{map\text{-}{\oplus }}\\ \mathsf{map\text{-}{\oplus }}\,{\mathbf{unfolds}}\,\mathsf{map};\; (\!\oplus\!)\\ \mathsf{map\text{-}{\oplus }} : (f:A\to B)\,(u:\mathsf{vec}\,m\,A)\,(v:\mathsf{vec}\,n\,A) \to \mathsf{map}\,f\,(u\oplus v) \equiv \mathsf{map}\,f\,u \oplus \mathsf{map}\,f\,v\\ \mathsf{map\text{-}{\oplus }}\,f\,{[\hspace {0.1pt}]}{}\,v = \mathsf{refl}\\ \mathsf{map\text{-}{\oplus }}\,f\,(a \mathbin {::}{} u)\,v = \mathsf{cong}\,((f\,a) \mathbin {::}{}-)\,(\mathsf{map\text{-}{\oplus }}\,f\,u\,v) \end{array} \end{align*}
Let us write
$\mathfrak{C}$
for the following type:
\begin{align*} & (f:A\to B)\,(u:\mathsf{vec}\,m\,A)\,(v:\mathsf{vec}\,n\,A) \to \mathsf{map}\,f\,(u\oplus v) \equiv \mathsf{map}\,f\,u \oplus \mathsf{map}\,f\,v \end{align*}
The above example is then elaborated as follows:
\begin{align*} \begin{array}{l} {\mathbf{prop}}\,\Upsilon _{\mathsf{map\text{-}{\oplus }}} = \Upsilon _{\mathsf{map}}\land \Upsilon _{\oplus }\\ \\[-5pt] \delta _{\mathsf{map\text{-}{\oplus }}} : \{\Upsilon _{\mathsf{map}}\land \Upsilon _{\oplus }\}\,\mathfrak{C}\\ \delta _{\mathsf{map\text{-}{\oplus }}}\,f\,{[\hspace {0.1pt}]}{}\,v = \mathsf{refl}\\ \delta _{\mathsf{map\text{-}{\oplus }}}\,f\,(a \mathbin {::}{} u)\,v = \mathsf{cong}\,((f\,a) \mathbin {::}{} -)\,(\delta _{\mathsf{map\text{-}{\oplus }}}\,f\,u\,v)\\ \\[-5pt] {\mathbf{const}}\, \mathsf{map\text{-}{\oplus }} : \lbrace \mathfrak{C} \mid \Upsilon _{\mathsf{map\text{-}{\oplus }}} \hookrightarrow \delta _{\mathsf{map\text{-}{\oplus }}} \rbrace \end{array} \end{align*}
Expression-level unfolding
The elaboration of the expression-level unfolding construct
${\mathbf{unfold}}\,\kappa \,{\mathbf{in}}\,M$
to our core calculus factors through the elaboration of expression-level unfolding to top-level unfolding as described in Section 2.5; we return to this in Section 4.3.
4. The Elaboration Algorithm
We now formally specify our mechanism for controlled unfolding by more precisely defining the elaboration algorithm sketched in the previous section, starting with a precise definition of the target of elaboration, our core calculus
$\mathbf{TT}_{\mathbb{P}}$
.
4.1 The core calculus
$\mathbf {TT}_{\mathbb{P}}$
Our core calculus
$\mathbf{TT}_{\mathbb{P}}$
is intensional MLTT (Martin-Löf Reference Martin-Löf, Rose and Shepherdson1975) with dependent sums and products, a Tarski universe, etc., extended with (1) a collection of proof-irrelevant proposition symbols, (2) dependent products over propositions, and (3) extension types for those propositions (Riehl and Shulman Reference Riehl and Shulman2017).
In fact,
$\mathbf{TT}_{\mathbb{P}}$
is actually a family of type theories parameterized by a bounded meet semilattice
$(\mathbb{P},\top ,\land )$
whose underlying set
$\mathbb{P}$
is the set of proposition symbols of
$\mathbf{TT}_{\mathbb{P}}$
; the semilattice structure on
$\mathbb{P}$
axiomatizes the conjunctive fragment of propositional logic with
$\land$
as conjunction,
$\top$
as the true proposition, and
$\leq$
as entailment (where
$p\leq q$
is defined as
$p\land q = p$
), subject to the usual logical principles such as
$p\land q \leq p$
and
$p\land q \leq q$
and
$p \leq \top$
.
The language
$\mathbf{TT}_{\mathbb{P}}$
augments ordinary MLTT with a new judgment
$\Gamma \vdash p\,\textit{true}$
(for
$p\in \mathbb{P}$
) and the corresponding context extension
$\Gamma ,p$
(for
$p\in \mathbb{P}$
). The judgment
$\Gamma \vdash p\,\textit{true}$
states that the proposition
$p$
is true in context
$\Gamma$
, that is, the conjunction of the propositional hypotheses in
$\Gamma$
entails
$p$
while
$\Gamma ,p$
extends
$\Gamma$
with the hypothesis that
$p$
is true.
\begin{align*} & \frac { \Gamma \ \textit{ctx} \qquad p\in \mathbb{P} }{ \Gamma ,p\ \textit{ctx} } \quad\qquad \frac { p\in \mathbb{P} }{ \Gamma , p \vdash p\,\textit{true} } \quad\qquad \frac { \Gamma ,p \vdash {\mathscr{J}} \qquad \Gamma \vdash p\,\textit{true} }{ \Gamma \vdash \mathscr{J} } \\[5pt] & \frac { }{ \Gamma \vdash \top \,\textit{true} } \quad\qquad \frac { \Gamma \vdash p\,\textit{true} \qquad \Gamma \vdash q\,\textit{true} }{ \Gamma \vdash p\land q\,\textit{true} } \quad\qquad \frac { \Gamma \vdash p\,\textit{true} \qquad p\leq q }{ \Gamma \vdash q\,\textit{true} } \end{align*}
The dependent product
$\{p\}\,A$
is defined as an ordinary dependent product:
\begin{align*} &\frac { {\Gamma }, p \vdash A\ \textit{type} }{ {\Gamma } \vdash \{p\}\,A\ \textit{type} } \quad\qquad \frac { \Gamma , p \vdash\, M:{A} }{ \Gamma \vdash \langle p \rangle \,M : \{p\}\,A } \quad\qquad \frac { \Gamma \vdash M : \{p\}\,A \qquad \Gamma \vdash p\,\textit{true} }{ \Gamma \vdash M \mathbin {@} p : A }\\[5pt] &\quad\qquad \frac { \Gamma ,p \vdash\, M:A \qquad \Gamma \vdash p\, true}{\Gamma\vdash(\langle p \rangle M) \mathbin {@} p = M : A} \qquad\qquad \frac{\Gamma\vdash M:{p}A}{\Gamma\vdash M =\langle p \rangle(M \mathbin {@} p):\{p\}A} \end{align*}
The remaining feature of
$\mathbf{TT}_{\mathbb{P}}$
is the extension type
$\lbrace A\vert p \hookrightarrow a_{p} \rbrace$
. Given a proposition
$p\in \mathbb{P}$
and an element
$a_{p}$
of
$A$
under the hypothesis
$p$
, the elements of
$\lbrace A\vert p \hookrightarrow a_{p}\rbrace$
correspond to elements of
$A$
that equal
$a_{p}$
when
$p$
holds.
\begin{align*} &\frac { {\Gamma } \vdash A\ \textit{type} \qquad \Gamma ,p \vdash a_{p}:{A} }{ {\Gamma } \vdash \lbrace A\vert p \hookrightarrow a_{p}\rbrace \ \textit{type} } \quad \frac { \begin{array}{l} \Gamma \vdash a : A\\ \Gamma , p \vdash a_{p} : A \\ {\Gamma }, p \vdash a =a_{p}:A \end{array}}{ \Gamma \vdash \mathsf{in}_p\,a : \lbrace A\vert p \hookrightarrow a_{p} \rbrace } \qquad \frac { \Gamma \vdash a : \lbrace A\vert p \hookrightarrow a_{p} \rbrace }{ \Gamma \vdash \mathsf{out}_p\,a : A } \\[8pt] &\qquad\qquad \frac { \Gamma \vdash a : A }{ {\Gamma } \vdash \mathsf{out}_p(\mathsf{in}_p\,a) = a : A } \qquad \frac { \Gamma \vdash a : \lbrace A\vert p \hookrightarrow a_{p} \rbrace }{ {\Gamma } \vdash \mathsf{in}_p(\mathsf{out}_p\,a) = a : \lbrace A\vert p \hookrightarrow a_{p} \rbrace } \\[8pt] &\qquad\qquad\qquad \qquad\qquad \frac { \Gamma \vdash p\,\textit{true} \qquad \Gamma \vdash a : \lbrace A\vert p \hookrightarrow a_{p} \rbrace }{ {\Gamma } \vdash \mathsf{out}_p\,a = a_{p}:{A} } \end{align*}
4.2 Signatures over
$\mathbf{{TT}}_{\mathbb{P}}$
Our elaboration procedure takes as input a sequence of surface-language definitions and outputs a well-formed signature, a list of declarations over
$\mathbf{TT}_{\mathbb{P}}$
.
![]()
A signature is well-formed precisely when each declaration in
$\Sigma$
is well-formed relative to the earlier declarations in
$\Sigma$
. Our well-formedness judgment
$\vdash \Sigma \,\textit{sig} \longrightarrow \mathbb{P}, \Gamma$
computes from
$\Sigma$
the
$\mathbf{TT}_{\mathbb{P}}$
context
$\Gamma$
and proposition semilattice
$\mathbb{P}$
specified by
$\Sigma$
’s
$\mathbf{const}$
and
$\mathbf{prop}$
declarations, respectively.
The rules for signature well-formedness are standard except for the
${\mathbf{prop}}\,p \le q$
and
${\mathbf{prop}}\,p = q$
declarations, which extend
$\mathbb{P}$
with a new element
$p$
satisfying
$p \le q$
or
$p = q$
, respectively. Recalling that our core calculus
$\mathbf{TT}_{\mathbb{P}}$
is really a family of type theories parameterized by a semilattice
$\mathbb{P}$
, these declarations shift us between type theories, for example, from
$\mathbf{TT}_{\mathbb{P}}$
to TT
$_{\mathbb{Q}}$
, where
$\mathbb{Q} = \mathbb{P}[p \le q]$
is the minimal semilattice containing
$\mathbb{P}$
and an element
$p$
satisfying
$p \le q$
. This shifting between theories is justified by Remark 5.
\begin{align*} &\qquad\quad \frac { }{ \vdash \epsilon \,\textit{sig} \longrightarrow \{\top \}, \cdot } \qquad\qquad \frac { \vdash \Sigma \,\textit{sig} \longrightarrow \mathbb{P}, \Gamma \qquad \Gamma \vdash _{\mathbf{TT}_{\mathbb{P}}} A\,\textit{type} }{ \vdash (\Sigma ,\ {\mathbf{const}}\, x : A)\,\textit{sig} \longrightarrow \mathbb{P}, (\Gamma , x : A) }\\[5pt] &\frac { \vdash \Sigma \,\textit{sig} \longrightarrow \mathbb{P}, \Gamma \qquad q\in \mathbb{P} }{ \vdash (\Sigma ,\ {\mathbf{prop}}\, p \le q) \,\textit{sig} \longrightarrow \mathbb{P}[p \le q] , \Gamma \qquad \vdash (\Sigma ,\ {\mathbf{prop}}\, p = q) \,\textit{sig} \longrightarrow \mathbb{P}[p = q], \Gamma } \end{align*}
4.3 Bidirectional elaboration
We adopt a bidirectional elaboration algorithm which mirrors bidirectional type-checking algorithms (Coquand Reference Coquand1996; Pierce and Turner Reference Pierce and Turner2000). The top-level elaboration judgment
$\Sigma \vdash \vec {S} \rightsquigarrow \Sigma ^{\prime }$
takes as input the current well-formed signature
$\Sigma$
and a list of surface-level definitions
$\vec {S}$
and outputs a new well-formed signature
$\Sigma ^{\prime }$
.
We define
$\Sigma \vdash \vec {S} \rightsquigarrow \Sigma ^{\prime }$
in terms of three auxiliary judgments for elaborating surface-language types and terms; in the bidirectional style, we divide term elaboration into a checking judgment
$\Sigma ;\;\Gamma \vdash {\texttt {e}} \Leftarrow A \rightsquigarrow \Sigma ^{\prime },M$
taking a core type as input and a synthesis judgment
$\Sigma ;\;\Gamma \vdash {\texttt {e}} \Rightarrow A \rightsquigarrow \Sigma ^{\prime },M$
producing a core type as output. All three judgments take as input a signature
$\Sigma$
and a context (telescope) over
$\Sigma$
and output a new signature along with a core type or term.
We represent a surface-level definition
$S$
as a tuple:
\begin{equation*} ({\mathbf{def}}\,\vartheta :{\texttt {A}},\textit {abbrv?},\textit {abstr?},[\kappa _1,\ldots \kappa _n],{\texttt {e}}) \end{equation*}
In this expression,
$\vartheta$
is the name of the definiendum,
$\texttt {A}$
is the surface-level type of the definition, abbrv? and abstr? are flags governing whether
$\vartheta$
is an
$\mathbf{abbreviation}$
(resp., is
$\mathbf{abstract}$
),
$[\kappa _1,\ldots ,\kappa _n]$
are the names of the definitions that
$\vartheta$
unfolds, and
$\texttt {e}$
is the surface-level definiens.
The elaboration judgment elaborates each surface definition in sequence:

The rules for term and type elaboration are largely standard: for instance, we elaborate a surface-dependent product to a core-dependent product by recursively elaborating the first and second components. We single out two cases below: the boundary between checking and synthesis, and the expression-level
$\mathbf{unfold}$
.
\begin{align*} \frac {\begin{array}{l} \Sigma ;\;\Gamma \vdash {\texttt {e}} \Rightarrow A \rightsquigarrow \Sigma _1;\;M \\ \Sigma _1;\;\Gamma \vdash \mathsf{conv}\,A\,B\end{array} }{ \Sigma ;\;\Gamma \vdash {\texttt {e}} \Leftarrow B \rightsquigarrow \Sigma _1;\;M } \quad \frac {\begin{array}{l} \Sigma ;\;\Gamma ,\Upsilon _{\vartheta } \vdash {\texttt {e}} \Leftarrow A \rightsquigarrow \Sigma _1;\;M \qquad {\mathbf{let}}\,\chi := \textit {gensym}\,() \\ {\mathbf{let}}\,\Sigma _2 := \Sigma _1, {\mathbf{const}}\,\chi :\prod _{\Gamma }{\lbrace A\vert \Upsilon _{\vartheta } \hookrightarrow M\rbrace }\end{array} }{ \Sigma ;\;\Gamma \vdash {\mathbf{unfold}}\,\vartheta \,{\mathbf{in}}\,{\texttt {e}} \Leftarrow A \rightsquigarrow \Sigma _2;\; \mathsf{out}_{\Upsilon _{\vartheta }}\,\chi [\Gamma ] } \end{align*}
The first rule states that a term synthesizing a type
$A$
can be checked against a type
$B$
provided that
$A$
and
$B$
are definitionally equal; in order to implement this rule algorithmically, we need definitional equality to be decidable. Additionally, our (omitted) type-directed elaboration rules are only well-defined if type constructors are injective up to definitional equality, for example,
$A \to B = C \to D$
if and only if
$A = C$
and
$B = D$
.
Elaborating expression-level unfolding requires the ability to hoist a type to the top level by iterating dependent products over its context, an operation notated
$\prod _{\Gamma }$
above. Because
$\Gamma$
can hypothesize (the truth of) propositions, this operation relies crucially on the presence of dependent products
$\{p\}\,A$
.
5. Case Study: An Implementation in 
We have implemented our approach to controlled unfolding in the experimental
proof assistant (RedPRL Development Team, 2020);
is an implementation of cartesian cubical type theory (Angiuli et al. Reference Angiuli, Brunerie, Coquand, Hou (Favonia), Harper and Licata2021), a computational version of homotopy type theory whose syntactic metatheory is particularly well understood (Huber Reference Huber2019; Sterling Reference Sterling2021; Sterling and Angiuli Reference Sterling and Angiuli2021). The existing support for partial elements and extension types made
particularly hospitable for experimentation with elaborating controlled unfolding to extension types. The following example illustrates the use of controlled unfolding in
, where
$\mathsf{path}\,A\,x\,y$
is the cubical notion of propositional equality (
$x \equiv y$
):
\begin{align*} &{\mathbf{def}}\,{+} : \mathbb{N}\to \mathbb{N}\to \mathbb{N} :=\\ &\quad {\mathbf{elim}}\\ &\quad \mid \mathsf{zero} \Rightarrow {n \Rightarrow n}\\ &\quad \mid \mathsf{suc}\,\{\_ \Rightarrow \textit{ih}\} \Rightarrow {n \Rightarrow \mathsf{suc}\,\{\textit{ih}\,n\}}\\ &\quad \\ & {\mathbf{unfold}}\,{+}\\ &{\mathbf{def}}\,\mathsf{+0L}\, (x : \mathbb{N}) : \mathsf{path}\,\mathbb{N}\,\{{+}\,0\,x\}\,x :=\\ &\quad i \Rightarrow x\\ &\quad \\ & {\mathbf{def}}\,\mathsf{+0R} : (x : \mathbb{N})\to \mathsf{path}\,\mathbb{N}\,\{{+}\,x\,0\}\,x :=\\ &\quad {\mathbf{elim}}\\ &\quad \mid \mathsf{zero} \Rightarrow \mathsf{+0L}\,0\\ &\quad \mid \mathsf{suc}\,\{x\Rightarrow \textit{ih}\} \Rightarrow \\ &\qquad {\mathbf{equation}}\,\mathbb{N}\\ &\qquad \begin{array}[t]{ll} \mid {+}\,0\,\{\mathsf{suc}\,y\} & {=}[\mathsf{+0L}\,\{\mathsf{suc}\,y\}]\\ \mid \mathsf{suc}\,\{{+}\,x\,0\} & {=}[i \Rightarrow \mathsf{suc}\,\{\textit{ih}\,i\}]\\ \mid \mathsf{suc}\,x\, \end{array} \end{align*}
This example follows a common pattern: we prove basic computational laws (
$\mathsf{+0L}$
) by unfolding a definition, and then in subsequent results (
$\mathsf{+0R}$
) use these lemmas abstractly rather than unfolding. Doing so controls the size and readability of proof goals and explicitly demarcates which parts of the library depend on the definitional behavior of a given function.
We have also implemented the derived forms for expression-level unfolding:
\begin{align*} \begin{array}{l} {\mathbf{def}}\,\mathsf{two} : \mathbb{N} := {+}\,1\,1\\ {\mathbf{def}}\,\mathsf{thm} : \mathsf{path}\,\mathbb{N}\,\mathsf{two}\,2:= {\mathbf{unfold}}\,\mathsf{two}\,{+}\,{\mathbf{in}}\,i \Rightarrow 2 \\ {\mathbf{def}}\,\mathsf{thm\text{-}{}is\text{-}{}refl} : \mathsf{path\text{-}p}\,\{i\Rightarrow \mathsf{path}\,\mathbb{N}\,\mathsf{two}\,\{\mathsf{thm}\,i\}\}\,\{i\Rightarrow \mathsf{two}\}\,\mathsf{thm} := \\ \quad i\,j\Rightarrow {\mathbf{unfold}}\,\mathsf{two}\,{+}\,{\mathbf{in}}\,2 \end{array} \end{align*}
\begin{align*} \begin{array}{l} {\mathbf{def}}\,\mathsf{thm\text{-}{}is\text{-}{}refl^{\prime }} : \mathsf{path}\,\{\mathsf{path}\,\mathbb{N}\,\mathsf{two}\,2\}\,\{i\Rightarrow {\mathbf{unfold}}\,\mathsf{two}\,{+}\,{\mathbf{in}}\,\mathsf{two}\}\,\mathsf{thm}:= \\ \quad i\,j\Rightarrow {\mathbf{unfold}}\,\mathsf{two}\,{+}\,{\mathbf{in}}\,2 \end{array} \end{align*}
The third and fourth declarations above illustrate two strategies in
for dealing with a dependent type whose well-formedness depends on an unfolding; in
$\mathsf{thm\text{-}{}is\text{-}{}refl}$
, we use a dependent path type but only unfold in the definiens, whereas in
$\mathsf{thm\text{-}{}is\text{-}{}refl^{\prime }}$
we use a non-dependent path type but must unfold in both the definiens and in its type.
Our
implementation deviates in a few respects from the presentation in this paper: in particular, the propositions
$\Upsilon _{\kappa }$
are represented by abstract elements
$i_\kappa : \mathbb{I}$
of the interval via the embedding
$\mathbb{I}\hookrightarrow \mathbb{F}$
sending
$i$
to
$(i=_{\mathbb{I}}1)$
.
utilizes a standalone library to compute entailment of cofibrations called Kado (Hou (Favonia) Reference Hou (Favonia)2022), created by Kuen-Bang Hou (Favonia). To support our experiment, Favonia modified Kado to support inequalities of dimension variables
$i\leq _{\mathbb{I}} j$
in addition to the cofibrations needed for
’s core theory. As a result, the modifications to
were quite modest. After the changes to Kado – which could in principle be reused in any proof assistant for the same purpose – the entire change required only a net increase of 996 lines of OCaml code.
6. The Metatheory of
$\textbf{TT}_{\mathbb{P}}$
In Section 4, we described an algorithm elaborating a surface language with controlled unfolding to
$\mathbf{TT}_{\mathbb{P}}$
. In order to actually execute our algorithm, it is necessary to decide the definitional equality of types in
$\mathbf{TT}_{\mathbb{P}}$
; as is often the case in type theory, type dependency ensures that deciding equality for types also requires us to decide the equality of terms. In order to implement our elaboration algorithm, we therefore prove a normalization result for
$\mathbf{TT}_{\mathbb{P}}$
.
At its heart, a normalization algorithm is a computable bijection between equivalence classes of terms up to definitional equality and a collection of normal forms. By ensuring that the equality of normal forms is evidently decidable, this yields an effective decision procedure for definitional equality. In our case, we attack normalization through a synthetic and semantic approach to normalization by evaluation called STC (Sterling and Angiuli Reference Sterling and Angiuli2021; Sterling, Reference Sterling2021, Reference Sterling2025; Sterling and Harper Reference Sterling and Harper2021).
Neutral forms for
$\mathbf{TT}_{\mathbb{P}}$
. The semantic analysis of normalization by evaluation rests on the observation of Fiore (Reference Fiore2002) that normal forms, though not stable under arbitrary substitutions, are nonetheless stable under renamings – substitutions that replace variables with variables (not necessarily injective). Therefore, decisive aspects of the normalization algorithm can be expressed internally to a topos of variable sets (presheaves) over the category of contexts and renamings; in order to instrument the semantic normalization algorithm with its proof of correctness, one passes to a larger topos obtained from the former by gluing. STC then instantiates the standard topos model of MLTT to substantially simplify various details that would otherwise be exceedingly tedious by means of a form of higher-order abstract syntax.
This appealingly simple story for normalization is substantially complicated by the boundary law for extension types:
\begin{equation*} \frac {\Gamma \vdash p\,\textit{true}\qquad \Gamma , p \vdash {a_{p}}:{A}\qquad \Gamma \vdash a : \{ A\vert p \hookrightarrow a_{p} \} }{ {\Gamma } \vdash \mathsf{out}_p\,a = a_{p} : A} \end{equation*}
When defining normal forms for
$\mathbf{TT}_{\mathbb{P}}$
, we might naively add a neutral form
to represent
$\mathsf{out}_p$
. In order to ensure that normal and neutral forms correspond bijectively with equivalence classes of terms, however, we should only allow
to be applied in a context where
$p$
is not true; if
$p$
were true,
$\mathsf{out}_p\,{a}$
is already represented by the normal form for
$a_{p}$
.
A similar problem arises in the context of cubical type theory (Angiuli et al. Reference Angiuli, Brunerie, Coquand, Hou (Favonia), Harper and Licata2021; Cohen et al. Reference Cohen, Coquand, Huber and Mörtberg2017) where some equalities apply precisely when two dimensions coincide. The same problem arises: either renamings must exclude substitutions that identify two dimension terms, or neutral forms will not be stable under renamings. In their proof of normalization for cubical type theory, Sterling and Angiuli (Reference Sterling and Angiuli2021) refined neutral forms to account for this tension by introducing stabilized neutrals. Rather than cutting down on renamings, they expand the class of neutrals by allowing “bad” neutrals akin to
in a context where
$p$
is true. They then associate each neutral form with a frontier of instability: a proposition that becomes true when the neutral is no longer “stuck.” Crucially, although well-behaved neutrals may not be stable under renamings, the frontier of instability is stable and can therefore be incorporated into the internal language.
We adapt Sterling and Angiuli’s stabilized neutrals to the simplified setting of
$\mathbf{TT}_{\mathbb{P}}$
and establish its normalization theorem. In so doing, we refine the approach of op. cit. to obtain a fully constructiveFootnote 3 normalization proof. We also carefully spell out the details of the universe in the normalization model, correcting an oversight in an earlier revision of Sterling’s dissertation (Sterling Reference Sterling2021).
6.1 Type theories as categories with representable maps
While any number of logical frameworks are available (generalized algebraic theories (Cartmell Reference Cartmell1978), essentially algebraic theories (Freyd Reference Freyd1972), locally cartesian closed categories (Gratzer and Sterling Reference Gratzer and Sterling2020), etc.), Uemura’s categories with representable maps (Uemura, Reference Uemura2021, Reference Uemura2023) are particularly attractive because they express exactly the binding and dependency structure needed for type theory: a second-order version of generalized algebraic theories.
Definition 7. A category with representable maps (CwR)
$\mathscr{C}$
is a finitely complete category equipped with a pullback-stable class of representable maps
$\mathscr{R} \subseteq \mathsf{Arr}(\mathscr{C})$
such that pullback along
$f \in \mathscr{R}$
has a right adjoint (dependent product along
$f$
).
Definition 8. A morphism of CwRs is a functor between the underlying categories that preserves finite limits, representability of maps, and dependent products along representable maps.
Definition 9. CwRs, morphisms between them, and natural isomorphisms assemble into a
$(2,1)$
-category
$\mathbf{CwR}$
.
Uemura’s logical framework axiomatizes the category of judgments of
$\mathbf{TT}_{\mathbb{P}}$
as a particular category with representable maps
$\mathbb{T}$
. The finite limit structure of
$\mathbb{T}$
encodes substitution as well as equality judgments, while the class of representable maps carves out those judgments that may be hypothesized. Uemura (Reference Uemura2023) develops a syntactic method for presenting a CwR as a signature within a variant of extensional type theory, which he has rephrased in terms of second-order generalized algebraic theories in his doctoral dissertation (Uemura Reference Uemura2021). Although we will use the type-theoretic presentation for convenience, the difference between these two accounts is only superficial.
Each judgment of
$\mathbf{TT}_{\mathbb{P}}$
is rendered as a (dependent) sort, while operators are modeled by elements of the given sorts. In order to record whether a given judgment may be hypothesized, the sorts of the type theory are stratified by meta-sorts
$\star \subseteq \Box$
where
$A : \star$
signifies that
$A$
is a representable sort (i.e., a context-former) and can be hypothesized, whereas
$B : \Box$
cannot parameterize a framework-level dependent product.
Proposition 10. Let
$\mathbb{T}$
be the free category with representable maps generated by a given logical framework signature; then the groupoid of CwR functors
$\operatorname{hom}{\mathbf{CwR}}{\mathbb{T}}{\mathscr{E}}$
is equivalent to the groupoid of interpretations of the signature within
$\mathscr{E}$
.
We will often refer to a category with representable maps
$\mathbb{T}$
as a type theory; indeed, as the category of judgments of a given type theory,
$\mathbb{T}$
is a suitable invariant replacement for it.
Proposition 10 describes the universal property of a type theory generated by a given signature in a logical framework. Type theories qua CwRs thus give rise to a form of functorial semantics in which algebras (interpretations) arrange into a groupoid of CwR functors
$\operatorname{hom}{\mathbf{CwR}}{\mathbb{T}}{\mathscr{E}}$
.
This is an appropriate setting for studying the syntax of type theory, but it is somewhat inappropriate for studying the semantics of type theory – in which one expects models to correspond to structured CwFs (Dybjer Reference Dybjer, Berardi and Coppo1996) or natural models (Awodey Reference Awodey2018), which themselves arrange into a (2,1)-category. The second notion of functorial semantics, developed by Uemura in his doctoral dissertation (Uemura Reference Uemura2021), is a generalization of the theory of CwFs and pseudo-morphisms between them (Clairambault and Dybjer Reference Clairambault and Dybjer2014; Newstead Reference Newstead2018).
Note that we may always regard a presheaf category
$\mathbf{Pr}\,{\mathscr{C}}$
as a CwR with the representable maps being representable natural transformations, that is, families of presheaves whose fibers at representables are representable (Awodey Reference Awodey2018).
Definition 11. A model of a type theory
$\mathbb{T}$
is a category
$\mathbf{M}_\diamond$
together with a CwR functor
${\mathbf{M}}:{\mathbb{T}}\to {\mathbf{Pr}\,{\mathbf{M}_\diamond }}$
.
Models are arranged into a (2,1)-category
${\mathbf{Mod}}\,\mathbb{T}$
(see Appendix A). Essentially, a morphism of models
${\mathbf{M}}\to {\mathbf{N}}$
is given by a functor
${\alpha _\diamond }:{\mathbf{M}_\diamond }\to {\mathbf{N}_\diamond }$
together with a natural transformation
${\mathbf{M}}\to {\alpha ^{\ast}\mathbf{N}}\in \operatorname{hom}_{\mathbf{CwR}}({\mathbb{T}},{\mathbf{Pr}\,{\mathbf{M}_\diamond }})$
that preserves context extensions up to isomorphism; an isomorphism between morphisms of models is a natural isomorphism between the underlying functors satisfying an additional property.
For each CwR
$\mathbb{T}$
, Uemura has shown the following theorem:
Proposition 12. The (2,1)-category of models
${\mathbf{Mod}}\,\mathbb{T}$
has a bi-initial object
$\mathbf{I}$
, whose category of contexts
$\mathbf{I}_\diamond$
is the smallest full subcategory of
$\mathbb{T}$
closed under the terminal object and pullbacks along representable maps.
6.2 Encoding
$\mathbf{TT}_{\mathbb{P}}$
in the logical framework
We begin by defining the signature for a category with representable maps
$\mathbb{T}_0$
containing exactly the bare judgmental structure of
$\mathbf{TT}_{\mathbb{P}}$
, namely the propositions and the judgments for types and terms. In our signature, we make liberal use of the Agda-style notation for implicit arguments. As always,
$p$
ranges over
$\mathbb{P}$
:
\begin{align*} \begin{array}{l} \langle p \rangle :\star \\\mathsf{tp} \square \\ \mathsf{tm} : \mathsf{tp} \Longrightarrow \star \\ \_:\{u,v:\langle p \rangle \}\Longrightarrow u = v\\ \_:\{\_ : \langle \bigwedge _{i\lt n}p_i\rangle \}\Longrightarrow \langle p_k\rangle \\ \_:\{\_:\langle p_i\rangle ,\dots \}\Longrightarrow \langle {\bigwedge _{i\lt n} p_i}\rangle \end{array} \end{align*}
Note that already this signature encodes the necessary theory of propositions for
$\mathbf{TT}_{\mathbb{P}}$
. For instance, if
$p \le q$
in
$\mathbb{P}$
, then a combination of the final two implications in the signature implies
$\langle p \rangle \to \langle q \rangle$
. We next extend the above to include the type formers of
$\mathbf{TT}_{\mathbb{P}}$
, writing
$\mathbb{T}$
for the CwR generated by the full signature.
Notation 14. Given
$X : \{\_ : \langle p \rangle \}\Longrightarrow \square$
, we will write
$\{p\}\, X$
to further abbreviate the Agda-style implicit function space
$\{\_ : \langle p \rangle \}\to X$
. Note that
$\{p\}\,X$
still associates with the right and so
$\{p\} A \to B$
signifies
$\{p\} (A \to B)$
.
For instance, the following constants specify the rules of extension types given in Section 4.1:
\begin{align*} \begin{array}{l} \mathsf{ext}p : (A : \mathsf{tp}\,(a : \{p\}\, \mathsf{tm}{A})\Longrightarrow \mathsf{tp}\\ \mathsf{in}_p : (A : \mathsf{tp}\,(a : \{p\}\, \mathsf{tm}{A})\,(u : \mathsf{tm}{A})\,\{\_ : \{p\}\, u=a\} \Longrightarrow \mathsf{tm}(\mathsf{ext}p\,A\,a)\\ \mathsf{out}_p : (A:\mathsf{tp}\,(a: \{p\}\,\mathsf{tm}{A})\,(u:\mathsf{tm}(\mathsf{ext}p\,A\,a))\Longrightarrow \mathsf{tm}{A}\\ \_ : (A:\mathsf{tp}\,(a:\{p\}\,\mathsf{tm}{A})\,(u:\mathsf{tm}(\mathsf{ext}p\,A\,a))\,\{\_:\langle p \rangle \} \Longrightarrow \mathsf{out}_p\,A\,a\,u = a\\ \_ : (A:\mathsf{tp}\,(a:\{p\}\,\mathsf{tm}{A})\,(u:\mathsf{tm}{A})\,\{\_:\{p\}\, u = a\}\Longrightarrow \mathsf{out}_p\,A\,a\,(\mathsf{in}_p\,A\,a\,u) = u\\ \_ : (A:\mathsf{tp}\,(a:\{p\}\,\mathsf{tm}{A})\,(u:\mathsf{tm}(\mathsf{ext}p\,A\,a))\Longrightarrow \mathsf{in}_p\,A\,a\,(\mathsf{out}_p\,A\,a\,u) = u \end{array} \end{align*}
The full list of non-standard constants is specified in Figure 1. Once the signature is complete, we obtain from Uemura’s framework a category with representable maps
$\mathbb{T}$
together with a bi-initial model
$\mathbf{I}$
.
Figure 1.
The non-standard aspects of the LF signature for
$\textbf{TT}_{\mathbb{P}}$
.

6.3 The atomic figure shape and its universal property
For each context
$\Gamma$
and type
${\Gamma }, \Gamma \vdash A\ \textit{type}$
, it is possible to axiomatize the normal forms of type
$A$
; unfortunately, this assignment of sets of normal forms does not immediately extend to a presheaf on the category of contexts
$\mathbf{I}_\diamond$
, precisely because normal forms are not a priori closed under substitution. In fact, closing normal forms under substitution is the purpose of normalization, so we are not able to assume it beforehand.
Normal forms are, however, closed under substitutions of variables for variables (often called structural renamings), and in our case we shall be able to close them additionally under the “phase transitions”
${\Gamma ,\langle p \rangle }\to {\Gamma ,\langle q \rangle }$
when
$\Gamma , p \vdash q\,\textit{true}$
is derivable. We shall refer to these substitutions as atomic substitutions, and we wish to organize them into a category.
It is possible to inductively define a category of “atomic contexts” whose objects are those of
$\mathbf{I}_\diamond$
and whose morphisms are atomic substitutions, but this construction obscures a beautiful and simple (2,1)-categorical universal property first exposed by Bocquet et al. (Reference Bocquet, Kaposi and Sattler2021) that leads to a more modular proof. To explicate this universal property, first note that the theory
$\mathbb{T}_0$
axiomatizes exactly the structure of variables and phase transitions, and that the initial model
$\mathbf{I}$
of
$\mathbb{T}$
is, by restriction along
${\mathbb{T}_0}\to {\mathbb{T}}$
, also a model of
$\mathbb{T}_0$
.
Definition 15. An atomic substitution model over a fixed
$\mathbb{T}$
-model
$\mathbf{M}$
is given by a model
$\boldsymbol{\mathbf{A}}$
of the bare judgmental theory
$\mathbb{T}_0$
, together with a morphism of models
${\alpha }:{\boldsymbol{\mathbf{A}}}\to {\mathbf{M}}$
in
${\mathbf{Mod}}\,\mathbb{T}_0$
such that
$\alpha _{\mathsf{tp}}: \boldsymbol{\mathbf{A}(\mathsf{tp})}\to {\alpha }^{\ast}{(\mathbf{M}(\mathsf{tp}))}\in \mathbf{Pr}\,{\boldsymbol{\mathbf{A}}_\diamond }$
is an isomorphism.
Atomic substitution model over
$\mathbf{M}$
arrange themselves into a (2,1)-category, a full subcategory of
${\mathbf{Mod}}\,\mathbb{T}_0\downarrow \mathbf{M}$
. The following result is due to Bocquet et al. (Reference Bocquet, Kaposi and Sattler2021).
Proposition 16. The bi-initial atomic substitution model
$(\boldsymbol{\mathbf{A}}, {\alpha }:{\boldsymbol{\mathbf{A}}}\to {\mathbf{I}})$
over
$\mathbf{I}$
exists.
When
$(\boldsymbol{\mathbf{A}}, {\alpha }:{\boldsymbol{\mathbf{A}}}\to {\mathbf{I}})$
is the bi-initial atomic substitution model over
$\mathbf{I}$
as in Proposition 16, we shall refer to an object
$\Gamma \in \boldsymbol{\mathbf{A}}$
as an atomic context and a morphism
${\gamma }:{\Delta }\to {\Gamma }$
in
$\boldsymbol{\mathbf{A}}$
as an atomic substitution. We shall assume without loss of generality that
$\boldsymbol{\mathbf{A}}(\mathsf{tp}) = \alpha ^{\ast}\mathbf{I}(\mathsf{tp})$
so that the component
$\alpha _{\mathsf{tp}}$
is the identity map.
6.4 Computability spaces by gluing along the atomic figure shape
We shall use the bi-initial atomic substitution model over
$\mathbf{I}$
as a figure shape in the sense of Sterling (Reference Sterling2021, §4.3) to instantiate STC. Here, we transition into the 2-category of Grothendieck topoi, geometric morphisms, and geometric transformations, guided by a phase distinction between “object-space” and “meta-space” (Sterling Reference Sterling2021);Footnote 4 object-space refers to the object language embodied in the model
$\mathbf{I}$
, whereas meta-space refers to the metalanguage embodied in the model
$\boldsymbol{\mathbf{A}}$
. Later on, we will construct a glued topos in which we may speak of constructs that have extent in both object-space and meta-space. We follow Vickers (Reference Vickers, Aiello, Pratt-Hartmann and Van Benthem2007) and Anel and Joyal (Reference Anel, Joyal, Anel and Catren2021) in emphasizing the distinction between a topos
$\boldsymbol{\mathsf{x}}$
and the category of sheaves
$\mathbf{Sh}\,{\boldsymbol{\mathsf{x}}}$
presenting it:
Definition 17. We denote by
$\boldsymbol{\mathsf{I}}$
and
$\boldsymbol{\mathsf{A}}$
the object-space and meta-space topoi, respectively, with underlying categories of sheaves
$\mathbf{Sh}\,{\boldsymbol{\mathsf{I}}} = \mathbf{Pr}\,{\mathbf{I}_\diamond }$
and
$\mathbf{Sh}\,{\boldsymbol{\mathsf{A}}} = \mathbf{Pr}\,{\boldsymbol{\mathbf{A}}_\diamond }$
.
Definition 18. The functor
${\alpha _\diamond }:{\boldsymbol{\mathbf{A}}_\diamond }\to {\mathbf{I}_\diamond }$
gives rise under precomposition to a continuous and cocontinuous functor
${\mathbf{Pr}\,{\mathbf{I}_\diamond }}\to {\mathbf{Pr}\,{\boldsymbol{\mathbf{A}}_\diamond }}$
that shall serve as the inverse image part of an (essential) geometric morphism
${\alpha }:{\boldsymbol{\mathsf{A}}}\to {\boldsymbol{\mathsf{I}}}$
named the atomic figure shape.
That
${\alpha }:{\boldsymbol{\mathsf{A}}}\to {\boldsymbol{\mathsf{I}}}$
is essential means that its inverse image
${\alpha ^{\ast}}:{\mathbf{Sh}\,{\boldsymbol{\mathsf{I}}}}\to {\mathbf{Sh}\,{\boldsymbol{\mathsf{A}}}}$
has a left adjoint
${\alpha _!}:{\mathbf{Sh}\,{\boldsymbol{\mathsf{A}}}}\to {\mathbf{Sh}\,{\boldsymbol{\mathsf{I}}}}$
; from the point of view of presheaves, this is precisely the Yoneda extension of
${\alpha _\diamond }:{\boldsymbol{\mathbf{A}}_\diamond }\to {\mathbf{I}_\diamond }$
as depicted below:

Definition 19. We denote by
$\boldsymbol{\mathsf{G}}$
the closed mapping cylinder (Johnstone Reference Johnstone1977) of the geometric morphism
${\alpha }:{\boldsymbol{\mathsf{A}}}\to {\boldsymbol{\mathsf{I}}}$
; in other words,
$\mathbf{Sh}\,{\boldsymbol{\mathsf{G}}}$
is the comma category
${\mathbf{Sh}\,{\boldsymbol{\mathsf{A}}}}\downarrow {\alpha ^{\ast}}$
. We will write
${\boldsymbol {j}}:{\boldsymbol{\mathsf{I}}}\hookrightarrow {\boldsymbol{\mathsf{G}}}$
and
$\boldsymbol{{i}}: {\boldsymbol{\mathsf{A}}}\hookrightarrow {\boldsymbol{\mathsf{G}}}$
for the open and closed subtopos immersions.
Following Sterling (Reference Sterling2025), we shall refer to a sheaf on
$\boldsymbol{\mathsf{G}}$
as a computability space. A computability space
$X\in \mathbf{Sh}\,{\boldsymbol{\mathsf{G}}}$
is then identified with a family
${\pi _X}:{{\boldsymbol{i}}^{\ast}X}\to {\alpha^{\ast} {\boldsymbol{j}}^{\ast}X}$
in
$\mathbf{Sh}\,{\boldsymbol{\mathsf{A}}}$
. Because the assignment
$\pi _X$
is natural in computability spaces
$X$
, it corresponds to a 2-cell
${\pi }:{{\boldsymbol{j}}\circ \alpha }\to {{\boldsymbol{i}}}$
in the 2-category of Grothendieck topoi. The universal property of
$\boldsymbol{\mathsf{G}}$
is then expressed by the fact that
${\pi }:{\boldsymbol{{j}}\circ \alpha }\to {{\boldsymbol {i}}}$
is a co-comma cell in the 2-category of Grothendieck topoi:

6.4.1 Reflection of object and meta-space
By definition, the inverse image functors
${j}^{\ast},{i}^{\ast}$
have fully faithful right adjoints
${j}_{\ast}:{\mathbf{Sh}\,{\boldsymbol{\mathsf{I}}}}\hookrightarrow {\mathbf{Sh}\,{\boldsymbol{\mathsf{G}}}}$
and
${i}_{\ast}:{\mathbf{Sh}\,{\boldsymbol{\mathsf{A}}}}\hookrightarrow {\mathbf{Sh}\,{\boldsymbol{\mathsf{G}}}}$
,respectively. These are computed as follows:
\begin{align*} {j}_{\ast}E &= (E, {1_{\alpha ^{\ast}E}}:{\alpha ^{\ast}E}\to {\alpha ^{\ast}E})\\ {i}_{\ast}A &= (\mathbf {1}{\mathbf{Sh}\,{\boldsymbol{\mathsf{I}}}}, {!_{A}}:{A}\to {{\mathbf{Sh}\,{\boldsymbol{\mathsf{A}}}}\cong \alpha ^{\ast}{\mathbf{Sh}\,{\boldsymbol{\mathsf{I}}}}}) \end{align*}
Thus, the adjunctions
${j}^{\ast}\dashv {j}_{\ast}$
and
${i}^{\ast}\dashv {i}_{\ast}$
exhibit
$\mathbf{Sh}\,{\boldsymbol{\mathsf{I}}}$
and
![]()