jcreed blog > A Small Modal Type Theory for Internal Parametricity

A Small Modal Type Theory for Internal Parametricity

Here's another iteration of the idea I keep noodling with. My goal is to really clarify the minimum that's needed to express internalized parametricity in a style that feels aesthetically pleasant given my type-theoretic upbringing.

Some tl;dr facts about the system:

I'm going describe a modal type theory with two syntactic "levels", called $\wid{\hbox{wide}}$ and $\nar{\hbox{narrow}}$, consistently colored so. Each of the two levels incorporate all the usual stuff you'd expect to find in a dependent type theory, and we're going to introduce two type formers to connect them together. There will be different kinds of hypotheses in the context, including familiar ones $x : \wid A$, but also "weak assumptions" $x \div \nar A$, and "strong assumption" $x :: \wid A$.

Motivating Example

If we have a polymorphic function $q$ of type $(X : \wid\rtype) \to X \to X$ then, by parametricity, $q$ ought to be the identity. Internalized parametricity means that we should be able to prove this fact internally. What this looks like is that in the context \[ \nar\Gamma = (\wid q :: (X : \wid\rtype) \to X \to X, \] \[ \nar A \div \nar\rtype,\ \nar R \div \nar A \to \nar\rtype,\ \nar a \div \nar A,\ \nar a' \div \nar R\ \nar a) \] there does exist a term $\nar M$ such that \[ \nar\Gamma \nprov \nar M : \nar R\ (\wid q\ \nar A\ \nar a) \] In other words, for any type $\nar A$ and any unary relation $\nar R$, if we have an element $\nar a$ of $\nar A$ that does satisfy the relation $\nar R$ (with $\nar a'$ being the witness) then it also holds that $\wid q$ applied to $\nar a$ satisfies $\nar R$.

We can substitute $\nar R := \lambda\nar b.\ \nar b \equiv \nar a$ and $\nar a' = \mathsf{refl}$ to get \[ [\mathsf{refl}/\nar a'][\lambda\nar b.\ \nar b \equiv \nar a/R]\nar M: q\ \nar A\ \nar a \equiv \nar a \] which says exactly that $\wid q$ is the identity. If we substitute the actual identity function for $\nar M$, we will find that \[ [\lambda X.\lambda x . x / \wid q][\mathsf{refl}/\nar a'][\lambda\nar b.\ \nar b \equiv \nar a/R]\nar M \equiv \mathsf{refl} \] That is, the expression actually computes to $\mathsf{refl}$.

What determined which things in this example were "wide" and "narrow"? Wide things intuitively are those "equipped with parametricity data" and narrow things are those that are not. Specifically, a wide type can be thought of as "a type equipped with a relation". Crucially, since we have an entire copy of dependent type theory living at the wide level, we can write ordinary programs without explicitly thinking about how to manipulate parametricity data.

Language

Now let's describe the syntax of the language. In both levels the context can carry several sorts of variable. Variables may be ordinary $x : \wid A$, strong $x :: \wid A$, or weak $x \div \nar A$. Ordinary variables are not allowed in narrow contexts, however. One may in its place think of $x \div \nar A$ as the most unmarked "default" hypothetical judgment in a narrow context.

Throughout, wide judgments are written with the turnstile $\wprov$ and narrow judgments use $\nprov$. For terms and types we just give the things that are nonstandard. All the usual stuff (variables, dependent function and product types, introduction and elim fors) are all in both the wide and narrow levels. \[ \begin{array}{rrcl} \hbox{Wide Contexts}&\wid\Gamma&::=&\cdot \celse \wid\Gamma, x :: \wid A \celse \wid\Gamma, x \div \nar A \celse \wid\Gamma, x : \wid A\\ \hbox{Narrow Contexts}&\nar\Gamma&::=&\cdot \celse \nar\Gamma, x :: \wid A \celse \nar\Gamma, x \div \nar A\\ \hbox{Wide Types}&\wid A&::=&\cdots \celse \gg(x \div \nar A).\nar B\\ \hbox{Narrow Types}&\nar A&::=&\cdots \celse \pp{\nar M}{\wid A}\\ \hbox{Wide Terms}&\wid M&::=&\cdots \celse \epair{\nar M}{\nar N} \celse \bgel(\nar M, \nar N)\\ \hbox{Narrow Terms}&\nar M&::=&\cdots \celse \{\wid M\} \celse \bungel(\wid M)\\ \end{array} \] The two new (relative to vanilla dependent type theory; I don't claim conceptual novelty, as they are extremely closely related to many types in the literature) type formers are:

Syntactic Operations

In order to give the typing rules for Glue and Fiber Types, we have to define a few operations first.

Erasure

Erasure $\erase{\dash}$ takes a wide type or term and turns it into a narrow type or term. \[ \begin{array}{rcl} \erase{(x : \wid A) \to \wid B}&=&(x : \erase{\wid A}) \to \erase{\wid B}\\ \erase{(x : \wid A) \x \wid B}&=&(x : \erase{\wid A}) \x \erase{\wid B}\\ \erase{\lambda x.\wid M}&=&\lambda x.\erase{\wid M}\\ \erase{\wid M\ \wid N}&=&\erase{\wid M}\ \erase{\wid N}\\ \erase x&=&x\\ \erase{\gg(x \div \nar A).\nar B}&=&\nar A\\ \erase{\bgel(\nar M, \nar N)}&=&\nar M\\ \erase{\epair{\nar M}{\nar N}}&=&\nar M\\ \erase{\wid\rtype}&=&\nar\rtype\\ \end{array} \] If we believe that wide things are "narrow things with parametricity data", then erasure simply returns the underlying narrow thing. It is a boring homomorphism on the usual constructs of dependent type theory, and is slightly interesting on the glue type former and intro form, and on the fiber elim form.

Inclusion

Narrow contexts are a subset of wide contexts. We write $\ups$ for the explicit inclusion of narrow contexts into wide contexts. \[ \begin{array}{rcl} \ups(\nar\Gamma, x :: \wid A)&:=&(\ups\nar\Gamma, x :: \wid A)\\ \ups(\nar\Gamma, x \div \nar A)&:=&(\ups\nar\Gamma, x \div \nar A)\\ \ups(\cdot)&:=&\cdot\\ \end{array} \]

Promotion and Demotion

The operations $\promote{\dash}$ and $\demote{\dash}$ both take a wide context to a narrow context. Demotion turns ordinary variables into weak variables and leaves other variables alone; promotion turns ordinary variables into strong variables and leaves other variables alone. \[ \begin{array}{rcl} \promote{(\wid\Gamma, x : \wid A)}&:=&(\promote{\wid\Gamma}, x :: \wid A)\\ \promote{(\wid\Gamma, x :: \wid A)}&:=&(\promote{\wid\Gamma}, x :: \wid A)\\ \promote{(\wid\Gamma, x \div \nar A)}&:=&(\promote{\wid\Gamma}, x \div \nar A)\\ \promote{(\cdot)}&:=&\cdot\\ \end{array} \qquad \begin{array}{rcl} \demote{(\wid\Gamma, x : \wid A)}&:=&(\demote{\wid\Gamma}, x \div \erase{\wid A})\\ \demote{(\wid\Gamma, x :: \wid A)}&:=&(\demote{\wid\Gamma}, x :: \wid A)\\ \demote{(\wid\Gamma, x \div \nar A)}&:=&(\demote{\wid\Gamma}, x \div \nar A)\\ \demote{(\cdot)}&:=&\cdot\\ \end{array} \] As abbreviations, we define two roundtrips from wide contexts to wide contexts: \[ \rdemote{\wid A} = \ups(\demote{\wid A}) \qquad \rpromote{\wid A} = \ups(\promote{\wid A}) \]

Typing Rules

Variable Rules

The variable rules give part of the story of the meaning of the different hypothetical judgments. Weak variables can't always be used: only when constructing a narrow term. Strong variables and ordinary variables can always be used whenever they appear. The difference between them is really in their interaction with the demotion operator above: strong variables survive demotion, whereas normal variables do get demoted to weak. \[ { x : \wid A \in \wid\Gamma \over \wid\Gamma \wprov x : \wid A } \qquad { x :: \wid A \in \wid\Gamma \over \wid\Gamma \wprov x : \wid A } \] \[ { x \div \nar A \in \nar\Gamma \over \nar\Gamma \nprov x : \nar A } \qquad { x :: \wid A \in \nar\Gamma \over \nar\Gamma \nprov x : \erase{\wid A} } \]

Context Formation

I don't have a snappy way to explain here the fiddly context manipulations that govern context validity, but they derive ultimately from a chain of adjunctions. \[ { {} \over \wprov \cdot \rctx } \qquad { {} \over \nprov \cdot \rctx } \qquad { \wprov \wid\Gamma \rctx \qquad \wid\Gamma \wprov \wid A : \rtype \over \wprov (\wid\Gamma, x : \wid A) \rctx } \] \[ { \wprov \wid\Gamma \rctx \qquad \demote{\wid\Gamma} \nprov \nar A : \rtype \over \wprov (\wid\Gamma, x \div \nar A) \rctx } \qquad { \wprov \wid\Gamma \rctx \qquad \rdemote{\wid\Gamma} \wprov \wid A : \rtype \over \wprov (\wid\Gamma, x :: \wid A) \rctx } \] \[ { \nprov \nar\Gamma \rctx \qquad \nar\Gamma \nprov \nar A : \rtype \over \nprov (\nar\Gamma, x \div \nar A) \rctx } \qquad { \nprov \nar\Gamma \rctx \qquad \ups\nar\Gamma \wprov \wid A : \rtype \over \nprov (\nar\Gamma, x :: \wid A) \rctx } \]

The Fiber Type

Here are the typing rules for the fiber type. We can introduce it by providing a wide term $\wid M$, which yields evidence that its erasure, $\erase{\nar M}$, really belongs to the relation of type $\wid A$. The elimination rule lets us combine an element of the underlying narrow type $\erase{\wid A}$ of $\wid A$ together with a proof of $\pp {\nar M} {\wid A}$, to yield a term of type $\wid A$. \[ { \ups\nar\Gamma \wprov \wid A : \wid\rtype \quad \nar\Gamma \nprov \nar M : \erase{\wid A} \over \nar\Gamma \nprov \pp{\nar M}{\wid A} : \nar\rtype } \qquad { \ups\nar\Gamma \wprov \wid M : \wid A \over \nar\Gamma \nprov \{\wid M\} : \pp{\erase{\wid M}}{\wid A} } \] \[ { \demote{\wid\Gamma} \nprov \nar M : \erase{\wid A} \quad \promote{\wid\Gamma} \nprov \nar N : \pp{\nar M}{\wid A} \over \wid\Gamma \wprov \epair{\nar M}{\nar N} : \wid A } \] Definitional equality includes the following conversions.
If $\nar\Gamma \nprov \nar N : \pp{\nar M}{\wid A}$ then we can do an $\eta$-expansion \[ \nar N \equiv_\eta \{\epair{\nar M}{\nar N}\} \] and we have a $\beta$-reduction \[ \epair{\nar M}{\{\wid N\}} \equiv_\beta \wid N \]

The Glue Type

Here are the typing rules for the glue type. We can introduce it by providing a base element $\nar M$ and an element $\nar N$ that witnesses that $\nar M$ "belongs to the relation" $\nar B$. And given an element of the glue type, we can eliminate it, obtaining a proof that the erased glue type element belongs to the relation $\nar B$. \[ { \demote{\wid\Gamma} \nprov \nar A : \nar\rtype \qquad \promote{\wid\Gamma}, x \div \nar A \nprov \nar B : \nar\rtype \over \wid\Gamma \wprov \gg(x \div \nar A).\nar B : \wid\rtype } \] \[ { \demote{\wid\Gamma} \nprov \nar M : \nar A \qquad \promote{\wid\Gamma} \nprov \nar N : [\nar M/ x]\nar B \over \wid\Gamma \wprov \bgel(\nar M, \nar N) : \gg(x \div \nar A).\nar B } \] \[ { \ups\nar\Gamma \wprov \wid M : \gg(x \div \nar A).\nar B \over \nar\Gamma \nprov \bungel \wid M : [\erase{\wid M}/ x]\nar B } \] Definitional equality includes the following conversions.
If $\wid\Gamma \wprov \wid M : \gg(x \div \nar A).\nar B$ then we can do an $\eta$-expansion \[ \wid M \equiv_\eta \bgel(\erase{\wid M}, \bungel \wid M) \] and we have a $\beta$-reduction \[ \bungel(\bgel(\nar M, \nar N)) \equiv_\beta \nar N \]

Interesting Theorems

Returning to the Identity Example

Now we can prove that there is $\nar M$ such that \[ \nar\Gamma \nprov \nar M : \nar R\ (q\ \nar A\ \nar a) \] Namely, it's \[\nar M = \bungel(\wid q\ (\gg(x \div \nar A).\nar R\ x)\ (\bgel(\nar a, \nar a'))) \] We take the function $\wid q$, apply it to the glue type that reifies the relation $\nar R$ as a single wide type $\gg(x \div \nar A).\nar R\ x$, and then apply it to a further argument $\bgel(\nar a, \nar a')$ which packages up the fact that we know $\nar a$ is an element satisfying the appropriate relation. It's a good exercise to go through the typing derivation and see where it's crucial that $\wid q$ is a strong hypothesis.

After substituting $\nar R := \lambda\nar b.\ \nar b \equiv \nar a$ and $\nar a' = \mathsf{refl}$ we would get \[ \nar\Gamma \nprov \bungel(\wid q\ (\gg(x \div \nar A).\ x \equiv \nar a)\ (\bgel(\nar a, \mathsf{refl}))) : q\ \nar A\ \nar a \equiv \nar a \] and further substituting $\wid q := \lambda X.\lambda x . x$, we would get \[ \nar\Gamma \nprov \bungel((\lambda X.\lambda x . x)\ (\gg(x \div \nar A).\ x \equiv \nar a)\ (\bgel(\nar a, \mathsf{refl}))) : (\lambda X.\lambda x . x)\ \nar a \equiv \nar a \] We can do some ordinary function $\beta$-reductions to get \[ \nar\Gamma \nprov \bungel(\bgel(\nar a, \mathsf{refl})) : \nar a \equiv \nar a \] and do one further $\beta$-reduction on the glue type to get \[ \nar\Gamma \nprov \mathsf{refl} : \nar a \equiv \nar a \]

The identity example is a special case; we can prove some nice incremental theorems that let us massage around parametricity information and extract the free theorem of a type internally.

The Nondependent Function Type

If \[ \nprov \nar\Gamma \rctx \qquad \ups\nar\Gamma \wprov \wid A : \rtype \qquad \ups\nar\Gamma \wprov \wid B : \rtype \qquad \nar\Gamma \nprov \nar f : \erase{\wid A \to \wid B} \] then there exists an isomorphism \[ \nar\Gamma \nprov \pp{\nar f}{\wid A \to \wid B} \cong (a : \erase{\wid A})(a' : \pp{a}{\wid A}) \to \pp{\nar f\ a}{\wid B} \] That is: a function is parametric exactly when it maps parametric arguments to parametric results. The two directions are \[ \mathsf{fore} = \lambda f'.\lambda a.\lambda a'.\ \{(\epair{\nar f}{f'})\ (\epair{a}{a'})\} \] \[ \mathsf{back} = \lambda k.\ \{\lambda x.\ (\epair{\nar f\ x}{k\ x\ \{x\}})\} \]

The Universe

For any type \[ \nar\Gamma \nprov \nar A : \nar\rtype \] there is an isomorphism \[ \nar\Gamma \nprov \pp{\nar A}{\wid\rtype} \cong (\nar A \to \nar\rtype) \] That is: to make a type parametric is exactly to equip it with a unary relation. The two directions are \[ \mathsf{fore} = \lambda p.\lambda a.\ \pp{a}{\epair{\nar A}{p}} \] \[ \mathsf{back} = \lambda R.\ \{\gg(x \div \nar A).\ R\ x\} \] checking the round trips requires using univalence and then one more "back and forth" for each round trip, but this can be done.