PFPL Chapter 14 Generic Programming

This part is not shown on PFPL preview version.

Introduction

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:ρρ, we wish to extend f to a transformation from type [ρ/t]τ to [ρ/t]τ by applying f to various spots in the inputs, where ρ occurs to obtain a value of type ρ, leaving the rest of data structure alone.

τ can be nat×t and f can be extended to nat×ρnat×ρ that transform a,b to a,f(b).

Ambiguity and Type Operator

Ambiguity arises in many-one nature of substitution. A type can have the form [ρ/t]τ in different ways, according to how t occur in τ.

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

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

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.τ such that t typeτ type.

An instance for a type operator t.τ i obtained by substituting t with ρ in τ.

Polynomial type operator is constructed from

  • type variable t
  • types void and unit
  • product type constructors τ1×τ2
  • sum type constructors τ1+τ2

Inductive Definition

t.t polyt.unit polyt.τ1 polyt.τ2 polyt.τ1×τ2 polyt.void polyt.τ1 polyt.τ2 polyt.τ1+τ2 poly

Closure under Substitution

If t.τ poly and t.τ poly, then t.[τ/t]τ poly.

By structural induction on t.τ 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×(nat+t) specifies all types ρ×(nat+ρ) for any choices of ρ.

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
Expe::=map{t.τ}(x.e)(e)map{t.τ}(x.e)(e)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.

Statics

t.τ polyΓ,x:ρe:ρΓe:[ρ/t]τΓmap{t.τ}(x.e)(e):[ρ/t]τ

  • abstractor x.e serves as a mapping from x:ρ to e:ρ.
  • generic extension of t.τ along with x.e specifies a mapping from [ρ/t]τ to [ρ/t]τ.

Dynamics

map{t.t}(x.e)(e)[e/x]emap{t.unit}(x.e)(e)emap{t.τ1×τ2}(x.e)(e)map{t.τ1}(x.e)(el),map{t.τ2}(x.e)(er)map{t.void}(x.e)(e)abort(e)map{t.τ1+τ2}(x.e)(e)case e{lx1lmap{t.τ1}(x.e)(x1)rx2rmap{t.τ2}(x.e)(x2)}

Preservation Theorem

If map{t.τ}(x.e)(e):τ and map{t.τ}(x.e)(e)e, then e:τ.

Positive Type Operators

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

t.τ1τ2 is a positive type operator if

  • t does not occur in τ1
  • t.τ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 τ1τ2 is analogous to implication ϕ1ϕ2, which is classically equivalent to ¬ϕ1ϕ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.τ pos, which states that the abstractor t.τ is a positive type operator.
t.t post.unit post.τ1 post.τ2 post.τ1×τ2 post.void post.τ1 post.τ2 post.τ1+τ2 posτ1 typet.τ2 post.τ1τ2 pos

Generic Extension

The generic extension follow similar definition as polynomial one with one more dynamics rule on function rule
map+{t.τ1τ2})(x.e)(e)λ(x:τ1) map+{t.τ2}(x.e)(e(x1))
Since t is not allowed in τ1, thus the type of result is τ1[ρ/t]τ2, assuming e is of type τ1[ρ/t]τ2.

If the result type is [ρ/t]τ1[ρ/t]τ2 given that e with type [ρ/t]τ1[ρ/t]τ2. Then we might see that the extension yield a function λ(x1:[ρ/t]τ1)(e((x1))).

The trouble is that we are given that map{t.τ1}(x.e)() transforms values of type [ρ/t]τ1 to [ρ/t]τ1. We might have to change the x1 type to fit it to e.

Exercise

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 map{x.τ}(x.e)(e) evaluated to e regardless of the choice of e.

If we extend this to positive type operators, then it will yield λ(x:τ1)e(x), which is not identical to e.

Database Schema

Since we know that database schema σ be iIτi, where first and last are in I and τfirst,τlast:str.

Let σ be the database schema type operator, with iIτi and τfirst,τlast:t as type variable.

σ can be [str/t]σ. Database type still follow the old convention nat×(natσ).

Finally the generic extension has form map{t.nat×(natσ)}(x.c(x))(d) where d be database.

Non-Negative Occurrence

t.t non-negt.τ1 negt.τ2 non-negt.τ1τ2 non-negt.τ1 non-negt.τ2 negt.τ1τ2 non-neg

(Non) Negative Generic Extension

map- -{t.t}(x.e)(e)[e/x]emap- -{t.τ1τ2}(x.e)(e)λ(x1:[ρ/t]τ1) map- -{t.τ2}(x.e)(e(map{t.τ1}(x.e)(x1)))map{t.τ1τ2}(x.e)(e)λ(x1:[ρ/t]τ1) map{t.τ2}(x.e)(e(map- -{t.τ1}(x.e)(x1)))

Then the type operator t.(tbool)bool with function f of type (ρbool)bool and x.e can construct λ(g:ρbool)f(λ(x:ρ)g(e)) for generic extension.