PFPL Chapter 14 Generic Programming

This part is not shown on PFPL preview version.


Many programs are instances of a pattern in a particular situation. Sometimes types determine the pattern by a technique called (typed) generic programming.

Example: the natural number definition in Chapter 9 defines pattern of recursion on values of an inductive type, which is expressed as a generic program.

Consider a function $f:\rho\to\rho’$, we wish to extend $f$ to a transformation from type $\lbrack \rho/t\rbrack\tau$ to $\lbrack \rho/t\rbrack\tau$ by applying $f$ to various spots in the inputs, where $\rho$ occurs to obtain a value of type $\rho’$, leaving the rest of data structure alone.

$\tau$ can be $\text{nat}\times t$ and $f$ can be extended to $\text{nat}\times\rho\to\text{nat}\times\rho’$ that transform $\langle a,b\rangle$ to $\langle a,f(b)\rangle$.

Ambiguity and Type Operator

Ambiguity arises in many-one nature of substitution. A type can have the form $\lbrack\rho/t\rbrack\tau$ in different ways, according to how $t$ occur in $\tau$.

The ambiguity is resolved by giving a template that marks the occurrences of $t$ in $\tau$ at which $f$ is applied.

Such template is known as type operator $t.\tau$, which is a abstractor binding type variable $t$ and type $\tau$.

Polynomial Type Operators

A type operator is a type equipped with a designated variable whose occurrences mark the spots in the type where a transformation is applied. The abstractor has form $t.\tau$ such that $t\text{ type}\vdash\tau\text{ type}$.

An instance for a type operator $t.\tau$ i obtained by substituting $t$ with $\rho$ in $\tau$.

Polynomial type operator is constructed from

  • type variable $t$
  • types void and unit
  • product type constructors $\tau_1\times\tau_2$
  • sum type constructors $\tau_1+\tau_2$

Inductive Definition

\displaylines{\dfrac{}{t.t\text{ poly}}\\
\dfrac{}{t.\text{unit poly}}\\
\dfrac{t.\tau_1\text{ poly}\phantom{“”}t.\tau_2\text{ poly}}{t.\tau_1\times\tau_2\text{ poly}}\\
\dfrac{}{t.\text{void poly}}\\
\dfrac{t.\tau_1\text{ poly}\phantom{“”}t.\tau_2\text{ poly}}{t.\tau_1+\tau_2\text{ poly}}}

Closure under Substitution

If $t.\tau\text{ poly}$ and $t’.\tau’\text{ poly}$, then $t.\lbrack \tau/t’]\tau’\text{ poly}$.

By structural induction on $t’.\tau’\text{ poly}$, we can see that the conclusion is easily achieved.

Generic Extension

Polynomial type operators are templates for structure of data structure with slots for values of particular type.

Type operator $t.t\times(\text{nat}+t)$ specifies all types $\rho \times(\text{nat}+\rho)$ for any choices of $\rho$.

Thus a polynomial type operator designates points of interest in a data structure that have a common type.

Generic extension of a polynomial type operator is a form of expression with syntax
\text{Exp}&&e&&::=&&\text{map}\lbrace t.\tau\rbrace(x.e’)(e)&&\text{map}\lbrace t.\tau\rbrace(x.e’)(e)&&\text{generic extension}
It specifies a program that applies a given function to all values lying at points of interest in a compound data structure to obtain a new one with applications at those points.


\dfrac{t.\tau\text{ poly}\phantom{“”}\Gamma,x:\rho\vdash e’:\rho’\phantom{“”}\Gamma\vdash e:\lbrack\rho/t\rbrack\tau}{\Gamma\vdash\text{map}\lbrace t.\tau\rbrace(x.e’)(e):\lbrack\rho’/t\rbrack\tau}

  • abstractor $x.e’$ serves as a mapping from $x:\rho$ to $e’:\rho’$.
  • generic extension of $t.\tau$ along with $x.e’$ specifies a mapping from $\lbrack\rho/t\rbrack\tau$ to $\lbrack\rho’/t\rbrack\tau$.


\displaylines{\dfrac{}{\text{map}\lbrace t.t\rbrace(x.e’)(e)\longmapsto\lbrack e/x\rbrack e’}\\
\dfrac{}{\text{map}\lbrace t.\text{unit}\rbrace(x.e’)(e)\longmapsto e}\\
\dfrac{}{\text{map}\lbrace t.\tau_1\times\tau_2\rbrace(x.e’)(e)\longmapsto
\langle\text{map}\lbrace t.\tau_1\rbrace(x.e’)(e\cdot l),\text{map}\lbrace t.\tau_2\rbrace(x.e’)(e\cdot r)\rangle}\\
\dfrac{}{\text{map}\lbrace t.\text{void}\rbrace(x.e’)(e)\longmapsto\text{abort}(e)}\\
\dfrac{}{\text{map}\lbrace t.\tau_1+\tau_2\rbrace(x.e’)(e)\\\longmapsto\\\text{case }e\lbrace l\cdot x_1\hookrightarrow l\cdot\text{map}\lbrace t.\tau_1\rbrace(x.e’)(x_1) \shortmid r\cdot x_2\hookrightarrow r\cdot\text{map}\lbrace t.\tau_2\rbrace(x.e’)(x_2) \rbrace}}

Preservation Theorem

If $\text{map}\lbrace t.\tau\rbrace(x.e’)(e):\tau’$ and $\text{map}\lbrace t.\tau\rbrace(x.e’)(e)\longmapsto e’’$, then $e’’:\tau’$.

Positive Type Operators

Positive type operators extend the polynomial type operators to admit restricted forms of function types.

$t.\tau_1\to\tau_2$ is a positive type operator if

  • $t$ does not occur in $\tau_1$
  • $t.\tau_2$ is a positive type operator

Any occurrences of type variable $t$ in domain of a function type are negative occurrences, whereas any occurrences of $t$ in range of a function type are positive occurrence.

A positive type operator is one for which only positive occurrences of $t$ are allowed.

The origin of positive occurrence is that function type $\tau_1\to\tau_2$ is analogous to implication $\phi_1\supset\phi_2$, which is classically equivalent to $\neg\phi_1\vee\phi_2$, so the occurrences in domain are negative occurrence.

Positive type operators are closed under substitution, just like polynomial type operators.

Inductive Definition

Judgment $t.\tau\text{ pos}$, which states that the abstractor $t.\tau$ is a positive type operator.
\displaylines{\dfrac{}{t.t\text{ pos}}\\
\dfrac{}{t.\text{unit pos}}\\
\dfrac{t.\tau_1\text{ pos}\phantom{“”}t.\tau_2\text{ pos}}{t.\tau_1\times\tau_2\text{ pos}}\\
\dfrac{}{t.\text{void pos}}\\
\dfrac{t.\tau_1\text{ pos}\phantom{“”}t.\tau_2\text{ pos}}{t.\tau_1+\tau_2\text{ pos}}\\
\dfrac{\tau_1\text{ type}\phantom{“”}t.\tau_2\text{ pos}}{t.\tau_1\to\tau_2\text{ pos}}}

Generic Extension

The generic extension follow similar definition as polynomial one with one more dynamics rule on function rule
\dfrac{}{\text{map}^+\lbrace t.\tau_1\to\tau_2\rbrace)(x.e’)(e)\longmapsto\lambda(x_:\tau_1)\text{ map}^+\lbrace t.\tau_2\rbrace(x.e’)(e(x_1))}
Since $t$ is not allowed in $\tau_1$, thus the type of result is $\tau_1\to\lbrack\rho’/t\rbrack\tau_2$, assuming $e$ is of type $\tau_1\to\lbrack\rho/t\rbrack\tau_2$.

If the result type is $\lbrack\rho’/t\rbrack\tau_1\to\lbrack\rho’/t\rbrack\tau_2$ given that $e$ with type $\lbrack\rho/t\rbrack\tau_1\to\lbrack\rho/t\rbrack\tau_2$. Then we might see that the extension yield a function $\lambda(x_1:\lbrack\rho’/t\rbrack\tau_1)\dots(e(\dots(x_1)))$.

The trouble is that we are given that $\text{map}\lbrace t.\tau_1\rbrace(x.e’)(-)$ transforms values of type $\lbrack\rho/t\rbrack\tau_1$ to $\lbrack\rho’/t\rbrack\tau_1$. We might have to change the $x_1$ type to fit it to $e$.


Generic Extension of Const Type Op

It is easy to see that if the generic extension is applied on a constant type operator, where $t$ do not occur, then there will be no place for substitution, leaving $\text{map}\lbrace x.\tau\rbrace(x.e’)(e)$ evaluated to $e$ regardless of the choice of $e’$.

If we extend this to positive type operators, then it will yield $\lambda(x:\tau_1)e(x)$, which is not identical to $e$.

Database Schema

Since we know that database schema $\sigma$ be $\prod_{i\in I}\tau_i$, where first and last are in $I$ and $\tau_{first},\tau_{last}:\text{str}$.

Let $\sigma’$ be the database schema type operator, with $\prod_{i\in I}\tau_i’$ and $\tau_{first}’,\tau_{last}’:t$ as type variable.

$\sigma$ can be $\lbrack \text{str}/t\rbrack\sigma’$. Database type still follow the old convention $\text{nat}\times(\text{nat}\to\sigma)$.

Finally the generic extension has form $\text{map}\lbrace t.\text{nat}\times(\text{nat}\to\sigma)\rbrace(x.c(x))(d)$ where $d$ be database.

Non-Negative Occurrence

\displaylines{\dfrac{}{t.t\text{ non-neg}}\\
\dfrac{t.\tau_1\text{ neg}\phantom{“”}t.\tau_2\text{ non-neg}}{t.\tau_1\to\tau_2\text{ non-neg}}\\
\dfrac{t.\tau_1\text{ non-neg}\phantom{“”}t.\tau_2\text{ neg}}{t.\tau_1\to\tau_2\text{ non-neg}}}

(Non) Negative Generic Extension

\displaylines{\dfrac{}{\text{map}^{\text{- -}}\lbrace t.t\rbrace(x.e’)(e)\longmapsto\lbrack e/x\rbrack e’}\\
\dfrac{}{\text{map}^{\text{- -}}\lbrace t.\tau_1\to\tau_2\rbrace(x.e’)(e)\longmapsto\lambda(x_1:\lbrack\rho’/t\rbrack\tau_1) \text{ map}^{\text{- -}}\lbrace t.\tau_2\rbrace(x.e’)(e(\text{map}^{-}\lbrace t.\tau_1 \rbrace(x.e’)(x_1)))}\\
\dfrac{}{\text{map}^{-}\lbrace t.\tau_1\to\tau_2\rbrace(x.e’)(e)\longmapsto\lambda(x_1:\lbrack\rho/t\rbrack\tau_1) \text{ map}^{-}\lbrace t.\tau_2\rbrace(x.e’)(e(\text{map}^{\text{- -}}\lbrace t.\tau_1 \rbrace(x.e’)(x_1)))}}

Then the type operator $t.(t\to\text{bool})\to\text{bool}$ with function $f$ of type $(\rho\to\text{bool})\to\text{bool}$ and $x.e’$ can construct $\lambda(g:\rho’\to\text{bool})f(\lambda(x:\rho)g(e’))$ for generic extension.