What needs to have a type?

We will define a type T->T where the first T is the domain and the second T is the range. The -> acts as a type constructor.

T1->T2 says if given a type T1 a function will return a type T2

T ::= T->T

The problem with this is that there are no base cases. So we need base types. Base types are concrete types.

Here we add Bool

T ::= T->T | Bool

We can now type a lambda as following:

(λx: Bool.x): BoolBool

It can also be applied for App:

(((λx: Bool.x): BoolBool) true): Bool

Type Ascription

In general it is impossible to figure out a λ's input type from its output type. Function application "removes" information.

Type Rules

t1:T1T2t2:T1(t1 t2): T2TApp
Note

The context of a term is a list of all the bound variables and their types.

A type rule for variables is as follows

(xT)ΓΓx:TTVar

Syntax

t ::=λx:T.t | (t t) | x
v ::=λx:T.t
T ::=TT

Type Safety

Proof of Progress

if Γt:T then t is a value or tt, t

Proof.

Proof of Preservation

This involves the use of a few other lemmas.

Permutation Lemma

If Γt:t and Δ is a permutation of Γ, then deltat:T.

This says that the ordering of Γ doesn't matter. This is not always true.

In order to prevent this we prevent shadowing meaning a variable can't be used more than once. Languages like Haskell get around this by mangling variables and renaming them to be unique, this is called alpha reduction.

Proof.

By induction on terms:

Γx:T implies (xT)Γ by type inversion. By definition of permutation (xT)Δ so Δx:T by TVar.

Γ(λx:T1.t2):T1T2 by type inversion. The induction hypothesis says permutation holds for (xT1), Δt2:T2. Thus Δ(λx:T1.t2):T1T2 holds by TLambda

Γ(t1 t2):T2 implies there exists some Γt1:T1T2 and Γt2:T1 by type inversion. Induction hypothesis says permutation holds Δt1:T1T2. Thus Δ(t1 t2):T2 holds by TApp.

Weakening Lemma

If Γt:T and xdom(T) then (xS),Γt:T

This essentially says typing is invariant if unique variables are added to the context.

Preservation of Types Under Substitution

If (xS),Γt:T and Γs:S then Γ...

This essentially says typing is invariant with respect to replacing a well-typed variable with a well-typed term of the same type.

Proof.

The Proof

uhhh...

Simple Extensions

There are three ways to enrich a language:

  1. Extension - Add new syntax, new values, new types and associated inference rules
  2. Derived Forms - Add new syntax and new types defined in terms of existing constructs
  3. Libraries - Add new functionality by using the language to define new resuable constructs

Prefer 2 over 3

Base Types

Extend the definition of T to include arbitrary uninterpretable base types.

T::= ...| A | TT


Unit and ;

Unit is a type with a single value.

Syntax:

t::=...| unit
v::=...| unit
T::=...| Unit

Type Rules:

Γunit:Unit

Conservative Extensions

A conservative extension is an extension to a language that does not reference any other bits of the language. It does not affect how the language works.

Unit in this case is a conservative extension.

Derived Form:

t1;t2(λx:Unit.t2)t1,where xFV(t2)

Note

This assumes call by value evaluation semantics.

This is defining sequencing (;) such that t1 is evaluated before t2. The where condition also requires that x doesn't appear in t2 so that it does not affect the evaluation of t_2.

Derived forms are evaluated by expanding the syntax with their definition

Inference Rules:

t1t1t1;t2t1;t2ESeqFirst

The above rule requires t1 to be evaluated first.

unit;t2t2ESeqUnit

This rule takes the unit production of the first rule and removes it to evaluate t2

Type Rules:

Γt2:UnitΓt2:TΓt1;t2:T

Let Binding

Syntax

t::= ...| let x=t in t

Evaluation Rules

let x=t in t2[xv1]t2let x=t1 in t2let x=t1 in t2

Type Rules

Γt1 : T1(xT1),Γt2 : T2Γlet x=t1 in t2 : T2

Derived Forms

let x=t1 in t2  ((λx:T.t1) t2)

Some Proofs

Define e

e xx
e (λx.t)λx.e t
e (t1 t2)((e t1) (e t2))
e let x=t1 in t2

Pairs

Syntax

t::= ...| {t,t} | t.1 | t.2
v:: ...| v,v
T::= ...| T1\crossT2