Principles of Programming Languages Lecture Notes: Bu Cas Cs 520

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 37

BU CAS CS 520

Principles of Programming Languages


Lecture Notes
Hongwei Xi
Computer Science Department, Boston University
111 Cummington Street, Boston, MA 02215
2
Chapter 1
Simply-Typed Lambda-Calculus
1.1 Syntax
constants c ::= true [ false [ 0 [ 1 [ 1 [
operators op ::= + [ [ [ / [
terms t ::= c [ x [ if t
0
then t
1
else t
2
[ op(t) [ x : T.t [ t
1
(t
2
)
values v ::= c [ x : T.t
types T ::= Bool [ Int [ T
1
T
2
contexts ::= [ , x : T
1.2 Static Semantics
c true, false
c : Bool
(T-Bool)
c 0, 1, 1, . . .
c : Int
(T-Int)
t
0
: Bool t
1
: T t
2
: T
if t
0
then t
1
else t
2
: T
(T-If )
(op) = T
1
T
2
t : T
1
op(t) : T
2
(T-Op)
(x) = T
x : T
(T-Var)
, x : T
1
t : T
2
x : T
1
.t : T
1
T
2
(T-Abs)
t
1
: T
1
T
2
t
2
: T
1
t
1
(t
2
) : T
2
(T-App)
3
4 CHAPTER 1. SIMPLY-TYPED LAMBDA-CALCULUS
1.3 Dynamic Semantics
t
0
t

0
if t
0
then t
1
else t
2
if t

0
then t
1
else t
2
(E-If )
if true then t
1
else t
2
t
1
(E-IfTrue)
if false then t
1
else t
2
t
2
(E-IfFalse)
t t

op(t) op(t

)
(E-Op)
op(v) = v

op(v) v

(E-OpVal)
t
1
t

1
t
1
(t
2
) t

1
(t
2
)
(E-App1)
t
2
t

2
v
1
(t
2
) v
1
(t

2
)
(E-App2)
(x.t
1
)(v
2
) [x v
2
]t
1
(E-AppAbs)
1.4 Properties of Typing
Lemma 1 (Inversion) Given a typing derivation T :: t : T, the last applied typing rule in T is
uniquely determined by the syntactic structure of t.
Lemma 2 (Canonical Forms)
1. If v is a closed value of the type Bool , then v is either true or false.
2. If v is a closed value of the type Int, then v 0, 1, 1, . . . holds.
3. If v is a closed value of the type T
1
T
2
, then v is of the form x : T
1
.t.
Theorem 3 (Progress) Suppose that t is a closed and well-typed terms, that is, there exists a deriva-
tion T :: t : T. Then either t is a value or t t

holds for some term t

.
Proof We proceed by structural induction on T. Clearly, we only need to handle the cases where
t is not a value.
T is of the following form,
T
0
:: t
0
: Bool t
1
: T t
2
: T
if t
0
then t
1
else t
2
: T
(T-If )
where t = if t
0
then t
1
else t
2
.
t
0
is a value. Then t
0
is either true or false by Lemma 2. Hence, t t
1
or t t
2
according to t being true or false.
1.4. PROPERTIES OF TYPING 5
t
0
is not a value. By induction hypothesis on T
0
, t
0
t

0
for some t

0
. Hence, t
if t

0
then t
1
else t
2
.
T is of the following form,
(op) = T
1
T
2
t
1
: T
1
T
1
:: op(t
1
) : T
2
(T-Op)
where t = op(t
1
) and T = T
2
.
t
1
is not a value. Then t
1
t

1
by induction hypothesis on T
1
. Hence, t op(t

1
).
t
1
is a value. Then t v, where v is the value of op(t
1
).
T is of the following form,
T
1
:: t
1
: T
1
T
2
T
2
:: t
2
: T
1
t
1
(t
2
) : T
2
(T-App)
where t = t
1
(t
2
) and T = T
1
.
t
1
is not a value. Then by induction hypothesis on T
1
, t
1
t

1
for some t

1
. Hence,
t t

1
(t
2
).
t
1
is a value. Then by induction hypothesis on T
2
, t
2
t

2
for some t

2
. Hence, t t
1
(t

2
).
t
1
and t
2
are values. Then by Lemma 2, t
1
is of the form x : T.t

1
. Hence, t [x t
2
]t

1
.
Lemma 4 (Substitution) If , x : S t : T and s : S, then [x s]t : T.
Theorem 5 (Subject Reduction) If T :: t : T and t t

, then t

: T is derivable.
Proof We proceed by structural induction on T. Note that t is not a value since t t

holds.
T is of the following form,
T
0
:: t
0
: Bool T
1
:: t
1
: T T
2
:: t
2
: T
if t
0
then t
1
else t
2
: T
(T-If )
where t = if t
0
then t
1
else t
2
.
t
0
t

0
and t t

= if t

0
then t
1
else t
2
. By induction hypothesis on T
0
, we have
derivation T

0
:: t

0
: Bool . Therefore, t

: T can be derived as follows.


T

0
:: t

0
: Bool T
1
:: t
1
: T T
2
:: t
2
: T
if t

0
then t
1
else t
2
: T
(T-If )
t
0
= true and t t

= t
1
. Note T
1
:: t
1
: T and we are done.
t
0
= false and t t

= t
2
. Note T
2
:: t
2
: T and we are done.
6 CHAPTER 1. SIMPLY-TYPED LAMBDA-CALCULUS
T is of the following form,
(op) = T
1
T
2
t
1
: T
1
T
1
:: op(t
1
) : T
2
(T-Op)
where t = op(t
1
) and T = T
2
.
t
1
t

1
and t t

= op(t

1
). By induction hypothesis on T
1
, we have T

1
:: t

1
: T
1
.
Hence, t

: T can be derived as follows.


(op) = T
1
T
2
t
1
: T
1
T

1
:: op(t
1
) : T
2
(T-Op)
t
1
is a value and t t

= v for the value v of op(t


1
). Given the type of op, v must have
the type T
2
. Hence, t

: T is derivable.
T is of the following form,
T
1
:: t
1
: T
1
T
2
T
2
:: t
2
: T
1
t
1
(t
2
) : T
2
(T-App)
where t = t
1
(t
2
) and T = T
1
.
t
1
t

1
and t t

= t

1
(t
2
). By induction hypothesis on T
1
, we have T

1
:: t

1
: T
1
T
2
.
Hence, t

: T can be derived as follows.


T

1
:: t

1
: T
1
T
2
T
2
:: t
2
: T
1
t
1
(t
2
) : T
2
(T-App)
t
1
is a value and t
2
t

2
and t t

= t
1
(t

2
). By induction hypothesis on T
2
, we have
T

2
:: t

2
: T
2
. Hence, t

: T can be derived as follows.


T
1
:: t
1
: T
1
T
2
T

2
:: t

2
: T
1
t
1
(t
2
) : T
2
(T-App)
t
1
= x : T
1
.t

1
for some t

1
and t
2
is a value and t t

= [x t
2
]t

1
. Then T
1
is of the
following form
, x : T
1
t

1
: T
2
x : T
1
.t

1
: T
1
T
2
(T-Abs)
By the Substitution Lemma, [x t
2
]t

1
: T
2
is derivable. Note that t

= [x t
2
]t

1
and we are done.
1.5 Evaluation Contexts
evaluation contexts E ::= [] [ if E then t
1
else t
2
[ op(E) [ E(t) [ v(E)
Denition 6 A redex is a special form of term.
1.6. TYPE ERASUE AND TYPABILITY 7
if true then t
1
else t
2
is a redex and its reduction is t
1
.
if false then t
1
else t
2
is a redex and its reduction is t
2
.
op(v
1
) is a redex if op(v
1
) = v
2
and its reduction is v
2
.
(x : T.t)(v) is a redex and its reduction is [x v]t.
Assume that t
1
= E[t] and t
2
= E[t

], where t is a redex and t

is its reduction. Then we write t


1
t
2
and say that t
1
reduces to t
2
in one step. Let

be the reexive and transitive closure of .


Proposition 7 Assume E[t] = E

[t

], where t and t

are redexes. Then E = E

and t = t

.
Proof By structural induction on E.
Theorem 8 (Subject Reduction) Assume T :: t : T and t t

. Then t

: T is derivable.
Proof Assume that t = E[t
1
] and t

= E[t

1
], where t
1
is a redex and t

1
is the reduction of t
1
. The
proof proceeds by structural induction on E.
Lemma 9 Assume T :: t : T. Then t is a value or t = E[t
0
] for some evaluation context E and
redex t
0
.
Proof By structural induction on T.
Theorem 10 (Progress) Assume T :: t : T. Then t is a value or t t

for some term t

.
Proof Assume that t is not a value. By Lemma 9, t = E[t
0
] for some evaluation context E and
redex t
0
. Hence, we have t t

for t

= E[t

0
], where t

0
is the reduction of the redex t
0
.
1.6 Type Erasue and Typability
8 CHAPTER 1. SIMPLY-TYPED LAMBDA-CALCULUS
Chapter 2
Simple Extensions
2.1 Base Types
2.2 The Unit Type
2.3 Derived Forms: Sequencing and Wildcards
terms t ::= . . . [ t
1
; t
2
[ : Unit.t
t
1
t

1
t
1
; t
2
t

1
; t
2
(E-Seq)
unit; t
2
t
2
(E-SeqNext)
2.4 Ascription
terms t ::= . . . [ t as T
t t

t as T t

as T
(E-Ascribe)
v as T v
(E-AscribeVal)
2.5 Let Bindings
terms t ::= . . . [ let x = t
1
in t
2
t
1
t

1
let x = t
1
in t
2
let x = t

1
in t
2
(E-Let)
let x = v
1
in t
2
[x v
1
]t
2
(E-LetVal)
9
10 CHAPTER 2. SIMPLE EXTENSIONS
2.6 Pairs
types T ::= . . . [ T
1
T
2
terms t ::= . . . [ t
1
, t
2
[ t.1 [ t.2
values v ::= . . . [ v
1
, v
2

t
1
: T
1
t
2
: T
2
t
1
, t
2
: T
1
T
2
(T-Pair)
t : T
1
T
2
t.1 : T
1
(T-Proj1)
t : T
1
T
2
t.1 : T
2
(T-Proj2)
t
1
t

1
t
1
, t
2
t

1
, t
2

(E-Pair1)
t
2
t

2
v
1
, t
2
v
1
, t

(E-Pair2)
t t

t.1 t

.1
(E-Proj1)
v
1
, v
2
.1 v
1
(E-Proj1Val)
t t

t.2 t

.2
(E-Proj2)
v
1
, v
2
.2 v
2
(E-Proj2Val)
2.7 Tuples
2.8 Records
types T ::= . . . [ l
1
: T
1
, . . . , l
n
: T
n

terms t ::= . . . [ l
1
= t
1
, . . . , l
n
= t
n
[ t.l
t
i
: T
i
for i = 1, . . . n
l
1
= t
1
, . . . , l
n
= t
n
: l
1
: T
1
, . . . , l
n
: T
n

T-Record
2.9 Sums
terms t ::= . . . [ inl(t) [ inr(t) [ case t of inl(x) t
1
[ inr(x) t
2
2.10. VARIANTS 11
inl(t
1
) : T
1
+ T
2
t
1
: T
1
(T-Inl)
inr(t
2
) : T
1
+ T
2
t
2
: T
2
(T-Inr)
t : T
1
+ T
2
, x : T
1
t
1
: T , x : T
2
t
2
: T
case t of inl(x) t
1
[ inr(x) t
2
: T
(T-Case)
case inl(v) of inl(x) t
1
[ inr(x) t
2
[x v]t
1
(E-CaseInl)
case inr(v) of inl(x) t
1
[ inr(x) t
2
[x v]t
2
(E-CaseInr)
t t

case t of inl(x) t
1
[ inr(x) t
2
case t

of inl(x) t
1
[ inr(x) t
2
(E-Case)
2.10 Variants
2.11 General Recursion
terms t ::= . . . [ fix(t) [ letrec x : T
1
= t
1
in t
2
t : T T
fix(t) : T
(T-Fix)
t t

fix(t) fix(t

)
(E-Fix)
fix(x : T.t) [x fix(x : T.t)]t
(E-FixVal)
12 CHAPTER 2. SIMPLE EXTENSIONS
Chapter 3
Normalization
Denition 11 Given a term t, let l(t) be the least upper bound on the numbers of reduction steps
in reduction sequences starting from t.
By the Konigs lemma, l(t) = if and only if there is an innite reduction sequence starting from
t. We write t to mean l(t) < .
Denition 12 (Reducibility) For each type T, we dene a predicate R
T
on closed terms of type T.
T is a base type. Then R
T
(t) holds if t .
T = T
1
T
2
. Then R
T
(t) holds if t and R
T
1
(v
1
) and R
T
2
(v) hold whenever t

v
1
, v
2
.
T = T
1
T
2
. Then R
T
(t) holds if t and R
T
2
([x v
1
]t
2
) holds whenever t

x : T
1
.t
2
and
R
T
1
(v
1
).
Proposition 13 Assume that t is a closed expression of type T.
1. If R
T
(t), then t .
2. If R
T
(t) and t t

, then R
T
(t

).
3. If t is not a value and R
T
(t

) for every t

satisfying t t

, then R
T
(t).
Proof (1) and (2) are straightforward. We now prove (3) by structural induction on T.
T is a base type. Then l(t) max(0 1 + l(t

) [ t t

). Therefore, t , which implies


R
T
(t).
T = T
1
T
2
for some types T
1
and T
2
. Assume that t

v
1
, v
2
for some values v
1
and v
2
.
Since t is not a value, there exists a term t

of type T such that t t

v
1
, v
2
holds. Since
R
T
(t

), R
T
i
(v
i
) for i = 1, 2. Hence, R
T
(t) by the denition of R
T
.
T = T
1
T
2
for some types T
1
and T
2
. Assume that t

x : T
1
.t
2
. Since t is not a
value, there exists a term t

of type T such that t t

and t

x : T
1
.t
2
. Since R
T
(t

),
R
T
2
([x v
1
]t
2
) for every v
1
satisfying R
T
1
(v
1
). Hence, R
T
(t) by the denition of R
T
.
Therefore, (3) is valid.
13
14 CHAPTER 3. NORMALIZATION
Lemma 14 (Main lemma) Assume that t : T is derivable and : holds. If R
(x)
((x)) for
all x dom() = dom(), then R
T
(t[]).
Proof By structural induction on a derivation T of t : T.
T is of the following form,
T
0
:: t
0
: Bool T
1
:: t
1
: T T
2
t
2
: T
if t
0
then t
1
else t
2
: T
(T-If )
where t = if t
0
then t
1
else t
2
. By induction hypothesis on T
0
, R
Bool
(t
0
[]) holds. Also,
R
T
(t
1
[]) and R
T
(t
2
[]) hold by induction hypothese on T
1
and T
2
, respectively.
We now prove by induction on l(t
0
) that if R
Bool
(t
0
),R
T
(t
1
) and R
T
(t
2
), then R
T
(if t
0
then t
1
else t
2
).
Assume that t = R
T
(if t
0
then t
1
else t
2
) t

.
t
0
t

0
and t t

= if t

0
then t
1
else t
2
. Then l(t

0
) < l(t
0
) and by induction hypothesis
on t

0
, R
T
(t

) holds.
t
0
= true and t t

= t
1
. Then obviously R
T
(t

) holds.
t
0
= false and t t

= t
2
. Then obviously R
T
(t

) holds.
Hence by Proposition 13 (3), R
T
(t) holds.
We can now conclude that R
T
(t[]) holds as t[] = if t
0
[] then t
1
[] else t
2
[].
T is of the following form,
T
1
:: t
1
: T
1
T
2
T
2
:: t
2
: T
1
t
1
(t
2
) : T
2
(T-App)
where t = t
1
(t
2
) and T = T
2
. Assume : . By induction hypothesis on T
1
and T
2
, both
R
T
1
T
2
(t
1
[]) and R
T
2
(t
2
[]) hold.
We now prove by induction on l(t
1
) +l(t
2
) that for all terms t
1
and t
2
, R
T
1
T
2
(t
1
) and R
T
2
(t
2
)
implies R
T
2
(t
1
(t
2
)). Assume that t t

. There are three possibilities.


t
1
t

1
and t

= t

1
(t
2
). Since l(t

1
) + l(t
2
) < l(t
1
) + l(t
2
), R
T
2
(t

) holds by induction
hypothesis.
t
1
= v
1
for some value v
1
, t
2
t

2
and t

= t
1
(t

2
). Since l(t
1
) +l(t

2
) < l(t
1
) +l(t
2
), R
T
2
(t

)
holds by induction hypothesis.
t
1
= x : T
1
.t
11
for some term t
11
, t
2
= v
2
for some value v
2
and t

= [x v
2
]t
11
. Since
R
T
1
T
2
(t
1
) and R
T
2
(t
2
), R
T
2
(t

) by the denition of R
T
1
T
2
.
Therefore, R
T
(t) by Proposition 13 (3).
We can now conclude that R
T
2
(t[]) holds as t[] = t
1
[](t
2
[]).
T is of the following form,
, x : T
1
t
2
: T
2
T
1
:: x : T
1
.t
2
: T
1
T
2
(T-Abs)
15
where t = x : T
1
.t
2
and T = T
1
T
2
.
Assume : . Let t

= t[] = x : T
1
.t
2
[] and we need to show R
T
(t

). Assume R
T
1
(v
1
) for
some value v
1
. Then [x v
1
]t
2
[] = t
2
[[x v
1
]]. Note that [x v
1
] : , x : T
1
holds. By
induction hypothesis on T
1
, R
T
2
(t
2
[[x v
1
]]) holds. Therefore, R
T
(t

) by the denition of
R
T
.
The rest of cases are trivial.
Theorem 15 If t is a well-typed closed term, then t .
Proof By Lemma 14, R
T
(t). Therefore, t by Proposition 13 (1).
16 CHAPTER 3. NORMALIZATION
Chapter 4
References
4.1 Introduction
terms t ::= . . . [ ref(t) [ !t [ t
1
:= t
2
[ l
values v ::= . . . [ l
types T ::= . . . [ Ref(T)
Note that we use l for a reference, which is a value.
Here is an example where recursion is achieved through reference.
val fact: (int -> int) ref = ref (fn n => 0)
val _ = fact := (fn (n: int): int => if n = 0 then 1 else n * !fact (n-1))
4.2 Typing
t : T
ref(t) : Ref(T)
(T-Ref )
t : Ref(T)
!t : T
(T-DeRef )
t
1
: Ref(T) t
2
: T
t
1
:= t
2
: Unit
(T-Assign)
17
18 CHAPTER 4. REFERENCES
4.3 Evaluation
The existing evaluation rules can be augmented with a store straightforwardly. For instance, we now
have the following evaluation rules.
t
1
[ t

1
[

t
1
(t
2
) [ t

1
(t
2
) [

(E-App1)
t
2
[ t

2
[

v
1
(t
2
) [ v
1
(t

2
) [

(E-App2)
(x.t
1
)(v
2
) [ [x v
2
]t
1
[
(E-AppAbs)
Here are the new evaluation rules.
t [ t

ref(t) [ ref(t

) [

(E-Ref )
l , dom()
ref(v) [ l [ (, l v)
(E-RefVal)
!t [ !t

t [ t

(E-DeRef )
l dom()
!l [ (l) [
(E-DeRefVal)
l dom()
l := v [ unit [ [l := v]
(E-AssignVal)
4.4 Store Typings
(l) = T
[ l : Ref(T)
(T-Loc)
[ t : T
[ ref(t) : Ref(T)
(T-Ref )
[ !t : T
[ t : Ref(T)
(T-DeRef )
[ t
1
: Ref(T) t
2
: T
[ t
1
:= t
2
: Unit
(T-Assign)
4.5 Safety
Denition 16 A store is said to be well-typed with respect to a typing context and a store typing
, written [ if dom() = dom() and [ (l) : (l) for every l dom() = dom().
Theorem 17 (Type Preservation) If [ t : T, [ and t [ t

, then for some

, [

: T

and [

.
4.5. SAFETY 19
Theorem 18 (Progress) Suppose T :: [ t : T. Then either t is a value or for any store such
that [ , t [ t

holds for some t

and

.
20 CHAPTER 4. REFERENCES
Chapter 5
Exceptions
Exceptions provide a means to altering the normal control in the execution of a program. For
instance, the following example indicates a way to terminate the execution of a loop by executing
the break command.
while (test) {
...
if (something_is_true) break;
...
}
This can be readily implemented through the use of exceptions. A raised exception may be captured
later so as to be handled by an exception handler.
datatype binaryTree = E | B of binaryTree * binaryTree
fun isBraunTree (t: binaryTree): bool =
let
exception NotBraunTree
fun aux (E) = 0
| aux (B (t1, t2)) =
let
val ls = aux t1 and rs = aux t2
in
if ls = rs orelse ls = rs + 1 then 1 + ls + rs
else raise NotBraunTree
end
in
let
val _ = aux t
in
true
end handle NotBraunTree => false
end
21
22 CHAPTER 5. EXCEPTIONS
5.1 Raising and Handling Exceptions
constants c ::= . . . [ error
terms t ::= . . . [ raise(t) [ try t
1
with t
2
answers ans ::= v [ raise(v)
t : Exn
raise(t) : T
(T-Raise)
t
1
: T t
2
: Exn T
try t
1
with t
2
: T
(T-TryWith)
t t

raise(t) raise(t

)
(E-Raise)
raise(v)(t
2
) raise(v)
(E-Raise-App1)
v
1
(raise(v)) raise(v)
(E-Raise-App2)
t
1
t

1
try t
1
with t
2
try t

1
with t
2
(E-TryWith)
try v
1
with t
2
v
1
(E-TryWithVal)
try raise(v) with t
2
t
2
(v)
(E-TryWithExn)
Theorem 19 (Subject Reduction) Assume that T :: t : T and t t

. Then t

: T is
derivable.
Theorem 20 (Progress) Assume that T :: t : T. Then either t is an answer or t t

for some
term t

.
Chapter 6
Recursive Types
6.1 Examples
IntList = nil : Unit, cons : Int IntList)
IntList = X.nil : Unit, cons : Int X)
nil = nil = unit)
cons = x : Int.xs : tIntList.cons = x, xs)
isNil = xs.case xs of nil = u) true [ cons = p) false
hd = xs.case xs of nil = u) raise(EmptyList) [ cons = p) p.1
tl = xs.case xs of nil = u) raise(EmptyList) [ cons = p) p.2
T
1
= X.Int X
T
2
= X.X Int
f
1
= fix(f : Int T
1
.n : Int.f)
= (x : T
2
.x(x))(x : T
2
.x(x))
Stream = X.Unit Int X
Process = X.Int Int X
upFrom = fix(f : Int Stream.n : Int. : Unit.n f(n + 1))
Nats = upFrom(0)
In the presence of recursive types, we can construct a nonterminating function without using the
xed point operator fix.
datatype T = C of T -> T
fun f (x: T): T = case x of C g => g (x)
Note that the evaluation of f(C(f)) is nonterminating.
Here is a representation of untyped -terms through the use of higher-order abstract syntax.
23
24 CHAPTER 6. RECURSIVE TYPES
datatype T = Lam of T -> T | App of T * T
[x[ = x
[x.t[ = Lam(x : T.[t[)
[t
1
(t
2
)[ = App([t
1
[, [t
2
[)
6.2 Formalization
types T ::= . . . [ X [ X.T
fold([X X.T]T) = X.T
unfold(X.T) = [X X.T]T
U = X.T t : [X U]T
t : U
(T-Fold)
U = X.T t : U
t : [X U]T
(T-Unfold)
Chapter 7
Universal Types
7.1 System F
types T ::= X [ T T [ X.T
terms t ::= x [ x : T.t [ t
1
(t
2
) [ X.t [ t[T]
values v ::= x : T.t [ X.t
contexts ::= [ , x : T
Encoding Datatypes
Pairs Let us dene Pair(T
1
, T
2
) as X.(T
1
T
2
X) X.
pair(x, y) = X.p : T
1
T
2
X.p(x)(y)
fst(p) = p[T
1
](x : T
1
y : T
2
.x)
snd(p) = p[T
2
](x : T
1
y : T
2
.y)
Natural Numbers Let us dene Nat as X.X (X X) X. Then the two constructors Z
and S can be dened as follows.
Z = X.z : X.s : X X.z
S(n : Nat) = X.z : X.s : X X.s(n[X](z)(s))
Lists Let us dene List(T) as X.X (T X X) X. Then the two list constructors Nil
and Cons can be dened as follows.
Nil = X.nil : X.cons : T X X.nil
Cons(x : T)(xs : List(T)) = X.nil : X.cons : T X X.cons(x)(xs[X](nil)(cons))
7.2 Some Basic Properties
Denition 21 Given a type variable X, a type T and a context , we write [X T] for the
context

such that dom() = dom(

) and

(x) = [X T]((x)).
Lemma 22 Assume T ::

X; t : T and

X T
1
[type]. Then

X; [X T
1
] [X T
1
]t : [X
T
1
]T is derivable.
25
26 CHAPTER 7. UNIVERSAL TYPES

X [ctx]

X [ctx]

X T [ctx]

X , x : T [ctx]
X is in

X

X X [type]
(K-Var)

X T
1
[type]

X T
2
[type]

X T
1
T
2
[type]
(K-Fun)

X, X T [type]

X X.T [type]
(K-Uni)

X [ctx] (x) = T

X; x : T
(T-Var)

X; , x : T
1
t : T
2

X; x : T
1
.t : T
1
T
2
(T-Abs)

X; t
1
: T
1
t
2

X, t
2
: T
1

X; t
1
(t
2
) : T
2
(T-App)

X, X; t : T

X [ctx]

X; X.t : X.T
(T-Tabs)

X; t : X.T

X T
0
[type]

X; t[T
0
] : [X T
0
]T
(T-Tapp)
t
1
t

1
t
1
(t
2
) t

1
(t
2
)
(E-App1)
t
2
t

2
v
1
(t
2
) v
1
(t

2
)
(E-App2)
t
1
t

1
t
1
(t
2
) t

1
(t
2
)
(E-App2)
(x : T
1
.t
1
)(v
2
) [x v
2
]t
1
(E-AppAbs)
t[T] t

[T]
t t

(E-Tapp)
(X.t)[T] [X T]t
(E-TappTabs)
7.3. TYPE ERASURE 27
Proof The proof follows from structural induction on T.
Theorem 23 (Subject Reduction) Assume that T ::

X; t : T and t t

. Then

X; t

: T is
derivable.
Proof We proceed by structural induction on T.
T has the following form,
T
1
::

X; t
1
: X.T
1

X T
2
[type]

X; t
1
[T
2
] : [X T
2
]T
1
(T-Tapp)
where t = t
1
[T
2
] and T = [X T
2
]T
1
. We now have two subcases.
t
1
t

1
and t t

= t

1
[T
2
]. By induction hypothesis on T
1
, we have T

1
:: t

1
: X.T
1
for some T

1
, and therefore

X; t

: T is derivable.
t
1
= X.t

1
and t t

= [X T
2
]t

1
. Then T
1
has the following form:

X, X; t
1
: T
1

X [ctx]

X; X.t

1
: X.T
1
(T-Tabs)
where t = X.t
1
and T = X.T
1
. By Lemma 22,

X; [X T
2
]t

1
: [X T
2
]T
1
is derivable since contains no free occurrences of X. Note that t

= [X T
2
]t

1
and
T = [X T
2
]T
1
, and we are done.
The other cases can be handled similarly.
Theorem 24 (Progress) Assume T ::

X; t : T. Then t is a value or t t

holds for some term


t

.
Proof The proof follows from structural induction on T.
7.3 Type Erasure
We can dene a type erasure function [ [ as follows, which translates a term in System F into an
untyped -term.
[x[ = x [x : T.t[ = x.[t[ [t
1
(t
2
)[ = [t
1
[([t
2
[) [X.t[ = [t[ [t[T][ = [t[
Notice that for a value v in System F, [v[ may not necessarily be a value. Therefore, given a term
t in System F, [t[

v
0
does not necessarily imply that we have t

v for some value v such that


[v[ = v
0
. To have this property, we can impose a restriction on (T-Tabs) by requiring that t be a
value whenever the following rule is applied.

X, X; t : T

X [ctx]

X; X.t : X.T
(T-Tabs)
This restriction is often called value restriction.
28 CHAPTER 7. UNIVERSAL TYPES
7.4 Normalization for System F
Denition 25 Given a closed type T, a predicate R dened on the closed terms of the type T is a
reducibility candidate of type T if R satises the following conditions.
If R(t) then t .
If R(t) and t t

then R(t

).
If t is not a value and R(t

) whenever t t

, then R(t).
For instance, the predicate R(t) t dened on the closed terms of a given type T is a reducibility
candiate of the type T.
We use
typ
for a substitution that maps type variables to types and
red
for a nite map that
maps type variables to reducibility candidates. We write
red
:
typ
if for each X dom(
red
) =
dom(
typ
),
red
(X) is a reducibility candidate of type

(X). In addition, we write


typ
:

X if
dom(
typ
) =

X.
Denition 26 Assume that

X T [type] is derivable and
red
:
typ
:

X. We dene Red[
red
;
typ
; T]
as follows by structural induction on T.
T is a type variable. Then Red[
red
;
typ
; T] =
red
(T).
T = T
1
T
2
. Then Red[
red
;
typ
; T](t) if t and whenever t

x : T
1
[
typ
].t
2
, we have
Red[
red
;
typ
; T
2
]([x v
1
]t
2
) for each v
1
satisfying Red[(]
red
;
typ
; T
1
)(v
1
).
T = X.T
1
. Then Red[
red
;
typ
; T](t) if t and whenever t

X.t
1
, Red[
red
[X
R];
typ
[X T
2
]; T
1
]([X T
2
]t
1
) holds for each reducibility candidate R of T
2
.
Proposition 27 Red[
red
;
typ
; T] is a reducibility candidate of the type T[
typ
].
Proof The proof immedidately follows from structural induction on T.
Proposition 28 We have the following:
Red[
red
;
typ
; [X T
1
]T] = Red[
red
[X Red[
red
;
typ
; T
1
]];
typ
[X T
1
[
typ
]]; T]
Proof The proof immediately follows from structural induction on T.
Lemma 29 Assume T ::

X; t : T and
red
:
typ
:

X. Also, assume : [
typ
] and
Red[
red
;
typ
; (x)]((x)) for each x dom(). Then Red[
red
;
typ
; T](t[
typ
][]) holds.
Proof We proceed by structural induction on T.
Theorem 30 (Normalization) Assume that ; t : T is derivable. Then t holds.
Proof By Lemma 29, Red[[]; []; T](t) holds. Since Red[[]; []; T] is a reducibility candidate by Propo-
sition 27, t holds.
Chapter 8
Existential Types
8.1 Introduction
types T ::= . . . [ X.T
term t ::= . . . [ T
1
, t as T
2
[ open t
1
as X, x in t
2
values v ::= . . . [ T
1
, v as T
2

X S [type]

X; t : [X S]T

X; S, t as X.T : X.T
(T-Pack)

X; t
1
: X.T
1

X, X; , x : T
1
t
2
: T
2

X T
2
[type]

X; open t
1
as X, x in t
2
: T
2
(T-Unpack)
t t

T
1
, t as T
2
T
1
, t

as T
2
(E-Pack)
t
1
t

1
open t
1
as X, x in t
2
open t

1
as X, x in t
2
(E-Unpack)
open (T
1
, v as T
2
) as X, x in t
2
[x v][X T
1
]t
2
(E-UnpackVal)
8.2 Data Abstraction with Existentials
Pair[T
1
][T
2
] : X.pair : T
1
T
2
X, fst : X T
1
, snd : X T
2

Sum[T
1
][T
2
] : X.inl : T
1
X, inr : T
2
X, caseof : Y.X (T
1
Y ) (T
2
Y ) Y
8.3 Encoding Existentials
X.T = Y.(X.T Y ) Y
S, t as X.T = let x = t in Y.f : X.T Y.f[S](x)
open t
1
as X, x in t
2
= t
1
[T
2
](X.x : T
1
.t
2
)
29
30 CHAPTER 8. EXISTENTIAL TYPES
{*(T_1 * T_2),
{pair = \x:T_1.\y:T_2.{x, y}
fst = \p:T_1 * T_2. p.1
snd = \p:T_1 * T_2. p.2}}
{*(T_2 * T_1),
{pair = \x:T_1.\y:T_2.{y, x}
fst = \p:T_1 * T_2. p.2
snd = \p:T_1 * T_2. p.1}}
{*(forall X.(T_1 -> T_2 -> X) -> X),
{pair = \x:T_1.\y:T_2.\X.\p:T_1 -> T_2 -> X. p(x)(y),
fst = \p:forall X.(T_1 -> T_2 -> X) -> X.p[T_1](\x:T_1.\y:T_2.x),
snd = \p:forall X.(T_1 -> T_2 -> X) -> X.p[T_1](\x:T_1.\y:T_2.y)}}
{*(forall X.(T_1 -> X) -> (T_2 -> X) -> X),
{inl = \x:T_1.\X.\l:T_1 -> X.\r:T_2 -> X.l(x),
inr = \x:T_1.\X.\l:T_1 -> X.\r:T_2 -> X.r(x),
caseof =
\Y.\s:forall X.(T_1 -> X) -> (T_2 -> X) -> X.
\lc:T_1 -> Y.\rc:T_2 -> Y. s[Y](lc)(rc)
}}
8.3. ENCODING EXISTENTIALS 31
signature STACK =
sig
type T
val new: unit -> T
val isEmpty: T -> bool
val length: T -> int
val pop: T -> int * T
val push: int * T -> T
end
structure Stack: STACK =
struct
type T = int list
fun new () = []
val isEmpty = List.isEmpty
val length = List.length
fun pop (s: T): int * T =
case s of [] => raise EmptyStack | x :: xs => (x, xs)
fun push (e: int, s: T): T = e :: s
end
32 CHAPTER 8. EXISTENTIAL TYPES
Chapter 9
Type Reconstruction
It can be burdensome for the programmer to write types when programming. Therefore, there is an
immediate question as to whether we can nd a satisfactory approach that allows the programmer
to omit writing types and then infers the omitted types from the structure of a program. We present
a positive answer to this question in this section.
9.1 External Language
We present an external language for TFPL
0
. In this language, the programmer is allowed to omit
writing types when dening a function fun f(x) is e. On the other hand, the programmer is also
allowed to write (e : ) to indicate that the expression e must have type .
expressions e ::= x [ f [ b [ i [ op(e
1
, . . . , e
n
) [ if e then e
1
else e
2
[
[ e
1
, e
2
[ e.1 [ e.2 [
fun f(x) is e [ fun f(x :
1
) :
2
is e [
app(e
1
, e
2
) [ let x = e
1
in e
2
[ (e : )
Note that we dene the type erasure of (e : ) as [e[, that is, [(e : )[ = [e[.
9.2 Type Reconstruction Algorithm
We need the following syntax for presenting a type inference algorithm for TFPL
0
.
Existential Type Variables X
Types T ::= X [ bool [ int [ 1 [ T T [ T T
Contexts G ::= [ G, x : T
Type Constraints ::= [ T
1
.
= T
2
[
1

2
Substitution ::= [] [ [X ]
Given a substitution , the satisability of under is dened as follows.
is satised under if is ;
is satised under if is T
1
.
= T
2
and T
1
[] = T
2
[].
is satised under if is
1

2
and both
1
and
2
. are satised under
33
34 CHAPTER 9. TYPE RECONSTRUCTION
We say that a type constraint is satisable if is satisable under some substitution .
We rst introduce two kinds of judgments; a judgment G e T basically means that we
can generate T and for given G and e such that type constraint needs to be solved for typing e
with T under context G; a judgment G e T basically states that we can generate for given
G, e and T such that type constraint needs to be solved for typing e with type T under context
G. The rules for a bidirectional type inference algorithm are presented in Figure 9.1 and Figure 9.2.
The following theorem establishes the soundness of these rules.
Theorem 31 (Soundness) We have the following.
1. Asume that G e T is derivable. If is satisable under and dom() contains all
existential variables in the judgment G e T , then G[] [e[[] : T[] is derivable.
2. Asume that G e T is derivable. If is satisable under and dom() contains all
existential variables in the judgment G e T , then G[] [e[[] : T[] is derivable.
Proof (1) and (2) are proven simultaneously with structural induction on the derivations T of
G e T and G e T .
Lemma 32 Let be a substitution on existential variables. We have the following.
1. If G e T is derivable, then G[] e T[] [] is also derivable.
2. If G e T is derivable, then G[] e T[] [] is also derivable.
Proof (1) and (2) are proven simultaneously with structural induction on the derivations of G
e T and G e T .
The following theorem establishes the completeness of the presented type inference rules.
Theorem 33 (Completeness) Assume that e : is derivable. Then we have the following.
1. [e[ T is derivable for some T and and there exists such that T[] = and is
satisable under .
2. [e[ is derivable for some and is satisable.
Proof (1) and (2) are proven simultaneously with structural induction on the derivation of e : .
9.3 Mutual Recursion
We present both typing rules and type inference rules for handling mutual recursion.
types ::= [ (
1
, . . . ,
n
)
expressions e ::= [ fun f
1
(x
1
:
1
) :

1
is e
1
and. . . and fun f
n
(x
n
:
n
) :

n
is e
n
[ e#n
9.3. MUTUAL RECURSION 35
G b bool
(tc-bool-up)
G b T T
.
= bool
(tc-bool-dn)
G i int
(tc-int-up)
G i T T
.
= int
(tc-int-dn)
G x G(x)
(tc-var-up)
G x T T
.
= G(x)
(tc-var-dn)
(op) =
1

n
G e
1

1

1
G e
n

n

n
G op(e
1
, . . . , e
n
)
1

n
(tc-op-up)
(op) =
1

n
G e
1

1

1
G e
n

n

n
G op(e
1
, . . . , e
n
) T
1

n
T
.
=
(tc-op-dn)
G e bool G e
1
T
1
G e
2
T
2
G if e then e
1
else e
2
T
1

2
(tc-if-up)
G e bool G e
1
T
1
G e
2
T
2
G if e then e
1
else e
2
T
1

2
(tc-if-dn)
G e
1
T
1

1
G e
2
T
2

2
G e
1
, e
2
T
1
T
2

1

2
(tc-tup-up)
G e
1
T
1

1
G e
2
T
2

2
G e
1
, e
2
T
1
T
2

1

2
(tc-tup-dn)
G e
1
T
1

1
G e
2
T
2

2
G e
1
, e
2
X
1

2
X
.
= T
1
T
2
(tc-tup-dn-atom)
Figure 9.1: Type reconstruction rules for generating types constraints (I)
36 CHAPTER 9. TYPE RECONSTRUCTION
G e T
1
T
2

G e.1 T
1

(tc-fst-up)
G e X
G e.1 X
1
X
.
= X
1
X
2
(tc-fst-up-atom)
G e T X
G e.1 T
(tc-fst-dn)
G e T
1
T
2

G e.2 T
2

(tc-snd-up)
G e X
G e.2 X
2
X
.
= X
1
X
2
(tc-snd-up-atom)
G e X T
G e.2 T
(tc-snd-dn)
G, f : X
1
X
2
, x : X
1
e X
2

G fun f(x) is e X
1
X
2

(tc-fun-up)
G, f : T
1
T
2
, x : T
1
e T
2

G fun f(x) is e T
1
T
2

(tc-fun-dn)
G fun f(x) is e T
G fun f(x) is e X X
.
= T
(tc-fun-dn-atom)
G, f :
1

2
, x :
1
e
2

G fun f(x :
1
) :
2
is e
1

2

(tc-fun-anno-up)
G, f :
1

2
, x :
1
e
2

G fun f(x :
1
) :
2
is e T T =
1

2
(tc-fun-anno-dn)
G e
1
T
1
T
2

1
G e
2
T
1

2
G app(e
1
, e
2
) T
2

1

2
(tc-app-up)
G e
1
X
1

1
G e
2
T
2
G app(e
1
, e
2
) X
2

1

2
X
1
= T X
2
(tc-app-up-atom)
G app(e
1
, e
2
) T
2

G app(e
1
, e
2
) T
1
T
1
.
= T
2
(tc-app-dn)
G e
1
T
1

1
G, x : T
1
e
2
T
2

2
G let x = e
1
in e
2
T
2

1

2
(tc-let-up)
G e
1
T
1

1
G, x : T
1
e
2
T
2

2
G let x = e
1
in e
2
T
2

1

2
(tc-let-dn)
G e
G (e : )
(tc-anno-up)
G e
G (e : ) T
.
= T
(tc-anno-dn)
Figure 9.2: Type reconstruction rules for generating types constraints (II)
9.3. MUTUAL RECURSION 37
The type (
1
, . . . ,
n
) is for an expression that denes n functions mutually recursively and these
functions are of types
1
, . . . ,
n
, respectively.
,f
1
:
1

1
,...,f
n
:
n

n
,x
1
:
1
e
1
:

1
.
.
.
,f
1
:
1

1
,...,f
n
:
n

n
,x
n
:
n
e
n
:

n
fun f
1
(x
1
:
1
):

1
is e
1
and...and fun f
n
(x
n
:
n
):

n
is e
n
):(
1

1
,...,
n

n
)
(type-funs)
e : (
1
, . . . .
n
) 1 i n
e#i :
i
(type-choose)
,f
1
:
1

1
,...,f
n
:
n

n
,x
1
:
1
e
1

1
.
.
.
,f
1
:
1

1
,...,f
n
:
n

n
,x
n
:
n
e
n

n
fun f
1
(x
1
:
1
):

1
is e
1
and...and fun f
n
(x
n
:
n
):

n
is e
n
)(
1

1
,...,
n

n
)
1
...
n
(tc-funs-anno-up)
,f
1
:X
1
X

1
,...,f
n
:X
n
X
n
,x
1
:X
1
e
1
X

1
.
.
.
,f
1
:X
1
X

1
,...,f
n
:X
n
X

n
,x
n
:X
n
e
n
X

n
fun f
1
(x
1
) is e
1
and...and fun f
n
(x
n
) is e
n
)(X
1
X

1
,...,X
n
X

n
)
1
...
n
(tc-funs-up)
G e (T
1
, . . . , T
n
) 1 i n
G e#i T
i

(tc-choose-up)
G e (T
1
, . . . , T
n
) 1 i n
G e#i T T = T
i
(tc-choose-dn)
Notice that neither rule (tc-funs-dn) nor rule (tc-funs-anno-dn) is presented. There is probably
no need for such rules in practice. In case there is such a need, we can always use either rule
(tc-funs-up) or rule (tc-funs-anno-up) to synthesize a type and then form a type constraint
between the synthezied type and the type being checked against.

You might also like