Sei sulla pagina 1di 61

CS 6110: Ocaml Tutorial

Lee Gao
January 25, 2013
1. Binding
1 l et sixtyOneTen = 6110
2. Tuples and Datatypes
1 l et t1 : i nt i nt = ( 3 , 5)
2 l et t2 : s t r i ng bool char = ( moo , true , q )
3 l et t3 : uni t = ( )
1 type s ui t = Spades | Diamonds |
3. Pattern Matching
1 l et t1 : i nt i nt = . . .
2
3 l et ( a , b) = t1
4
5 l et ( , b) = t1
6
7 l et ( a , 5 ) = t1 ( Can match cons t ant s t oo ; i ncompl et e )
4. More pattern matching, with custom types
1 l et sui tname : s t r i ng =
2 match c with
3 Spades > spades | Diamonds > diamonds
4 | . . .
If you dont exhaustive specify all possibilities, OCaml will warn you.
1 l et b : bool = . . .
2 match b with
3 t r ue > . . .
4 | f a l s e > . . .
5. Bad pattern, shadowing
1
1 l et pai r = ( 42 , 611)
2 l et x = 611
3 match pai r with
4 ( x , 611) > 0
5 | ( 42 , x) > 1
6 | > 2
Shadows
6. Functions
1 l et square : i nt > i nt =
2 fun ( x : i nt ) > x x
3
iso
=
4 l et suqare ( x : i nt ) : i nt = x x
7. Recursive functions must have a rec annotation to tell top level to bind
itself into tis environment
1 l et rec x! =
2 i f x = 0 then 1
3 el se x ((x 1)! )
8. Tuple argument (using CHI is isomorphic)
1 l et f ( a , b) : i nt =
2 . . .
3
4 l et f ( p : i nt i nt ) : i nt =
5 . . .
By CHI, these are equivalent to the preferred style
1 l et f ( a : i nt ) ( b : i nt ) : i nt =
2 . . .
We call this currying, and say that f

curried f.
9. A minor tangent
We have
gcd : int * int -> int
gcd : int -> (int -> int)
Through currying and uncurrying, these types are somehow equiv-
alent (there exists some isomorph between these that preserves
behavior)
10. Polymorphism
2
1 l et i d x = x
This will have type , or in caml parlance
1 a > a
11. Polymorphic types:
1 type a l s t =
2 Empty
3 | Cons of ( a a l s t ) ( al s o r e c ur s i v e )
12. OCaml lists builtin
[] is the empty list
:: is the cons operator
@ is the append operator
[1; 2; 3] 1 :: 2 :: 3 :: []
13. @ is not constant time, its a bad idea.
1 l et rec r e ve r s e ( l : a l i s t ) : a l i s t =
2 match l with
3 [ ] > [ ]
4 | hd : : t l > ( r e ve r s e t l ) @ [ hd ]
14. Instead, we should write something more idiomatic like
1 l et rec r e ve r s e ( l : a l i s t ) : a l i s t =
2 l et rec r ever s e ( l : a l i s t ) ( l : a l i s t ) : a l i s t =
3 match l with
4 [ ] > l
5 | hd : : t l > r ever s e t l ( hd : : l ) in
6 r e ve r s e l [ ]
15. Load another script
1 #use . ml
3
CS 6110: January 28
Lee Gao
January 28, 2013
Pure Lambda:
e ::= x | e
0
e
1
| x.e
We also have a reduction such that
(x.e
1
) e
2

e
1
[x e
2
]
We also have an reduction as long as x is not free in e.
x.e x

A

e
And we say that A and e are extensionally equivalent. If we apply these
equivalence, we have reductions and expansions. Reductions are like the
steps of computation, while expansions are in reverse.
Alpha equivalence
e

e[x/x

] if x

not free in e
1 Lists
We have pair e
1
e
2
, fst p, snd p
Specication
rst(pair e
1
e
2
) e
1
second(pair e
1
e
2
) e
2
pair(rst p)(second p) p
We can have
pair a b = f.fab
so then
pair a.b.f.fab
So then
rst true, second false
1
rst p.p (ab.a)

true
snd p.p false
We can then build a linked list out of these pair/con constructs.
2 Let construct
In ocaml, the let x = e
1
in e
2
, which can be encoded as
let x = e
1
in e
2
(x.e
2
) e
1
3 Recursion
We can harness .
In ocaml, we need to do
1 l et rec f ( n) = i f n < 2 then 1
2 el se n f ( n1)
Dene
Fact n.If (n < 2) 1 (n Fact(n 1))
But how do we solve for Fact?
Lets dene something called F that is
F = f.n.If (n < 2) 1 (n F (n 1))
Then F Fact = n. (n Fact ), which is what we want. So F Fact =
Fact. So Fact is a xed point solution of F. To nd xed point, iteratively
rene your result at each point.
We can compute the xed point of any in .
Let X = (x.F(x x)) (x.F(x x))
By one simple reduction, we nd that X = F X, meaning that X is the
xed point of F.
Now, dene Y = f. (x.f(x x)) (x.f(x x)), so now, Y F returns X for
F which is the xed point of F.
Now, to dene the factorial function, let
F
Then
Fact Y F
And we can encode the let rec construct as
let rec f n = let f = Y f. in
2
4 Conuence
Theorem 1 (Conuence). Terms have unique normal form if that normal
form exists up to equivalence. Or
e

e
1
, e

e
2
= e

.e
1

e
2

Normal order recution: reduces leftmost redex at each step. Guaranteed to


reach the normal form. For example:
(xy.y)

I supposing that we reduce the innermost/leftmost redex


The applicative order: outside-to-inside, reduces order rst before applying:
natural order of how most PL works.
(xy.y)

(xy.y)

(xy.y)

.
.
.
5 Operational Semantics
How to run programs on an abstract turing machine?
Theres an idea, Structural operational semantics (SOS, introduced by Plotkins
et al):
5.1 Small-step Semantics
Were going to have a binary relation on terms e, : expr expr.
Were going to write e
1
e
2
means e
1
goes to e
2
in one computational step.
So to run a program, we just compute the transitive closure of e
0
on

up
until normal form (or nontermination).
We can dene this reduction inductively using inference rules.
5.1.1 CBV
e ::= x | e
1
e
2
| x.e
v ::= x.e
We want to have the reduction and congruence rules
(x.e) v e[x v]

e
1
e

1
e
1
e
2
e

1
e
2
Left
e
2
e

2
v e
2
v e

2
Right
These rules give left-to-right evaluation and are deterministic, but will not
nd the normal form for expressions that applies something to an equivalent
form of .
3
Alternatively, using the relation building syntax

e
1
, e

v e
1
, v e


Right-2
5.1.2 CBN Corresponds to the normal order of reduction
Were going to have arguments that are evaluated lazily (we avoid evaluating
the arguments until necessary).
We have the same denition of what a normal term is, but we replace
(x.e
1
) e
2
e
1
[x e
2
]

e
1
e

1
e
1
e
2
e

1
e
2
Left
This strategy never diverges if your term has a normal form. Used in Haskell,
Miranda, etc.
4
CS 6110: January 30
Lee Gao
January 30, 2013
1 Subtleties of Substitution
Suppose we have
(y (x.x y))[y x] = (x(x.x x))
This isnt what we want because were creating a new capture. So what we
want is a method of capture-avoiding substitution. In integral calculus
e

x=b
x=a
= e[x b] e[x a]
A rst defn of correct substitution came about in 1950. Were good at
avoiding this problem, but programs cant (they need to have a manual
alpha-renaming transformation on bad transforms).
1.1 Free Variables
Lets dene a function
Fv(e) : set of free variables
We want to dene this inductively where
Fv(x.x y) = {y}
Fv(x) = {x}
Fv(e
1
e
2
) = Fv(e
1
) Fv(e
2
)
Fv(x.e) = Fv(e)\ {x}
Fv doesnt expand out indenitely because its denition relies on subterms
e

, where if we were to ever create an ordering, there exists one where e

< e,
so Fv relies on strictly smaller terms (under some ordering relation), then
we will have guarantee on termination.
In fact, this monotone structure has a name: structural induction. Alterna-
tively, by induction on the height of e. Fixed Point Bitches!
1
1.2 Computing the substitution
Dene e

{e/x}, by structural induction on e, the terms (so case by case)


x{e/x} = e
Var
y {e/x} = y
Var-2
(e
1
e
2
) {e/x} = e
0
{e/x} e
1
{e/x}
App
y.e

{e/x}
Lambda
For that last case, we have three subcases:
1. x = y, then x gets shadowed, so = x.e

2. x = y y / Fv(e), so = x.e

{e/x}
3. x = y y Fv(e), here we should do some -renaming (change of
variable name).

y.e

{e/x} =

.e

/y

{e/x} where y

is fresh
Then, this becomes case 2.
In this context, y

is Fresh in this context means that


y

= x
y

/ Fvs(e)
y

/ Fvs(e

)
y / Fvs(x e e

)
In CBV and CBN, the argument is ALWAYS closed, we typically dont get
to a case where we need to worry about this kind of stu.
Why is this induction? We need to prove
Lemma 1 (Monotonicity). The height of a substitution e {e/x} < the height
of e

plus the height of e


2 Big-step Semantics ()
In small, its dicult to prove certain properties (but we need to establish
equivalence between and ).
Relation: e v, where e a symbolic variable for terms and v a symbolic
variable for value or a normal term.
: TermValue
Where only represents the termination evaluations.
2
2.1 Call By Value
v v
Val
e
1
x.e

e
2
v
2

{v/x} v

e
1
e
2
v

App
Its easy to build an interpreter directly from this denition. In caml
1 type term = Lambda of var term | App of termterm | Var of var
2 l et bstep e : value =
3 match e with
4 | Lambda( v , e ) > Lambda( v , e )
5 | App(e
0
, e
1
) >
6 l et Lambda( x , e ) = bstep e
0
in
7 l et v2 = bstep e
1
in
8 bstep s ubs t e x v
9 | > f a i l wi t h Cannot eval uat e a var i abl e
2.2 Call By Name
v v
Val
e
0
x.e

{e
1
/x} v
e
1
e
2
v
App
The substitution in App in CBN can be intractable, but some language
memoizes its value instead of copying this expression over and over again.
Even in eager languages, conditionals and guards ensures that not all code
are run, where in fully eager, we would expect to evaluate everything.
Big vs Small
Big:
more extensional
easier to prove properties about, since we only one proof tree rather
than a closure over the small semantics
easy to turn into an interpreter
fewer rules
Small:
more compositional, so certain features like nondeterminism like threads,
we can easily add these after building our semantic)
simpler rules
3
2.3 Nondeterministic choice operator
We add a new term
e
1
|e
2
to mean that either e
1
or e
2
. Nondeterministic:
e
1
v
e
1
| e
2
v
Left
e
2
v
e
1
| e
2
v
Right
Before, our semantic is syntax directed, but we no longer have a deterministic
choice on which term to apply. For example, if e
1
doesnt halt, but e
2
does,
our must be able to gure out. We call this angelic nondeterminism.
In small step, we can reduce either side.
e
1
e

1
e
1
| e
2
e

1
| e
2
Left
e
1
e
1
e
1
| e
2
e
1
| e

2
Right
v | e v
Choose-L
e | v v
Choose-R
4
CS 6110: January 30
Lee Gao
February 1, 2013
1 IMP
The language Imp has syntax
a ::= x | n | a
1
a
2
b ::= True | False | b | b
1
b
2
| b
1
b
2
| b
1
b
2
c ::= skip | x := a | c
1
; c
2
| if b then c
1
else c
2
| while b do c
One wuch algorithm
1 n := 999;
2 pri me := 0;
3 while pri me=0 do (
4 d := z ; n := n + 1;
5 pri me := 1;
6 . . .
7 )
1.1 Small step semantics
We want to extend our evaluation state with a symbolic environment , and
we have as our state, the pair or conguration c, , and our small step
relation will look like
c,

That is
: com com
Wlog, we dene the same for arithmetic and boolean expressions:
c,

a, a

b, b

1
We want the normal form to be skip, so
x := 2 + 3, {x 0} x := 5, {x 0}
skip, {x 5}
The nal congurations are those that do not step, the normal forms are
those with skip.
1.1.1 Arithmetic
n = (x)
x, n
Var
a
1
, a

1
a
1
a
2
, a

1
a
2
Circ
a
2
, a

2
n a
2
, n a

2
Circ-2
(n = n
1
+ n
2
)
n
1
n
2
, n
Circ-Normal
Normal form: n, this is why we do not allow the rule
n, n
Int
since this will fuck up everything
1.1.2 Booleans
b
1
, b

1
b
1
b
2
, b

1
b
2
Short-
False b
2
, False
Short--F
True b
2
, b
2
Short--T
2
1.1.3 Commands
a,

x := a,

x := a

,
Assgn
x := n, skip, [x n]
Assgn-Int
c
1
,

1
,

c
1
; c
2
,

1
; c
2
,

Seq-Left
skip; c
2
, c
2
,
Seq-Skip
b, b

if b then c
1
else c
2
if b

then c
1
else c
2
If
while b do c, if b then c; while b do c else skip,
While
1.2 Big Step Semantics
Were going to have
a, n
b, T
c,

skip,
Skip
a, n
x := b, [x n]
Assgn
c
1
,


c
2
,

c
1
; c
2
,

Seq
b, True c
1

if b then c
1
else c
2
,

If-T
b, False c
2

if b then c
1
else c
2
,

If-F
b, True c; while b do c,

while b do c,

While-T
b, False
while b do c,
While-F
3
Note that the unrolling rule is equivalent to
b, True c,


while b do c,

while b do c,

While-T
We can also establish command equivalence to the small step rule.
Theorem 1 (Command Equivalence). c,

c,

skip,

Suppose that while True do skip terminates, then


True, True skip, while True do skip,

while True do skip,

A
So this essentially becomes
.
.
.
while True do skip,

While
while True do skip,

While
This proof tree is not nite, hence this doesnt terminate.
4
CS 6110: Feb 4
Lee Gao
February 4, 2013
1 Inference Rules
When you dene a rule, youre really denintg a set of rule instances, that
with consistent substitution of metavariables that must also satisfy some
side conditions.
Now,
3 2 5
3 2 + 1 5 + 1
is a valid (albeit incorrect) instance of the rule. But if were at the axiom
leaves, then side condition must be obeyed as well.
A logical instance is just
x
1
x
2
x
3
. . .
x
Instance
so that x, x
i
S. Let the relation or whatever be dened as A (so that
= A in the case of the operational semantics, then A S.
Lets have a rule operator R(B), (a notion of entailment): what does the
things in B entail? (AKA, if were allowed to assume B, then
R(B) =

x |
x
1
. . . x
n
x
, {x
1
, . . . , x
n
} B

So R() is the set of axioms (that do not have premises). Note, if an axiom
has a side condition but no premise, then its still an axiom.
Consistency A R(A)
Closure R(A) A
These two conditions says that A = R(A). So A is a xed point of R. There
could potentially be an innite number of xed points of R, so we need to
pick the appropriate one.
1
A set of inference rules is an inductive denition. So A is the elements
derivable in a nite number of steps.
times set
0
1 step R()
2 R
2
()
.
.
.
.
.
.
So just get the xed point, aka
A =

n
R
n
()
Prove that this is a xed point.
R is monotonic, that is, if B C, then R(B) R(C). So
R() R
2
() . . .
So that

n
i
R
i
() = R
n
. So if some element shows up in these sets, then it
stays. So
x A = n.x R
n
()
Theorem 1 (Closure).
R(A) A
Proof. Let x R(A) where
R(A) = R

n
R
n
()

then it must be the case that x is the conclusion of some rule


x
1
. . . x
n
x
Instance
where x
1
, . . . , x
n
A (implicit: nite n). Therefore, each of x
1
, . . . , x
n
occurs in some R
n
. Now, pick some nite m such that all of x
1
, . . . , x
n

R
m
(). Then x R
m+1
() A; so x A, which concludes the proof.
Theorem 2 (Consistency).
A R(A)
Proof. Let x A, then there must exist some n such that x R
n
(A). Since
x R
n
() = x R(A), because
R
n1
() A = R
n
R(A)
which concludes the proof.
2
Therefore, A is a xed point of R.
Which xed point is it? It turns out that A is the least possible (smallest)
xed point of R.
Theorem 3 (Least FP). A is the smallest xed point of R
Proof. let B be a xed point of R, so B = R(B). Obviously, B, so
B = R() R(B) = B = . . .
So therefore

n
R
n
() B
which concludes the proof.
So its interesting to think about what the other fp do. The least xed
point is the intersection of all closed sets. The greatest fp is the union of all
consistent sets.
The greatest fp (max fp) allows innite proof. So for example, we can
have
x
x
?
so we can derive x arbitrarily as
.
.
.
x
?
x
?
x
?
so for the relation, the LFP gives the terminating executions and the
MFP gives that and also the nonterminating executions. MFP is also called
coinduction.
Do we really need to restrict rules to have a nite number of premises?
Lets build a rule for interesting
1 I
1
n

I n

= n + 1
n I
Next
m > n.m I
n I
Prev
So that
R() = {1}
R
2
= {1, 2}
.
.
.
R
n
= {1, . . . , n}
3
so

n
R
n
= {1, . . . } = N
but 0 R(N), so A isnt a xed point of R anymore.
Recall that we dened the free variables Fvs(e) inductively as
Fvs(x) = {x} Fvs(e
1
e
2
) = Fvs(e
1
) Fvs(e
2
)
Fvs(x.e) = Fvs(e)\ {x}
then we an dene the relation meaning that e has free variables {. . . },
so that
x {x}
Var
e
1
v
0
e
2
v
2
v = v
2
v
1
e
1
e
2
v
App
e v
x.e v\ {x}
Lam
Theorem 4. Exactly one v for each e such that e v.
Proof. By induction on the height of e. In the base case, we have height 0,
so e = x. Here, theres only one rule that applies, which shows the case.
Next, the inductive step
e = e
0
e
1
. By induction, theres a unique v
0
, v
1
such that e
0
v
0
and
e
1
v
1
. Then there is a unique set v = v
0
v
1
, and the rule gives
that e v, which also shows the case.
e = x.e Same exact reasoning, appealing to uniqueness preservation
of v\ {x}
Were allowed to do this because theres only one rule that applies to each
argument, and the argument on the RHS is smaller.
Its awkward to prove based on the height of the proof tree. Lets now move
onto well-founded induction, which uses the concept of the well-founded
relations:
4
CS 6110: Feb 4
Lee Gao
February 6, 2013
1 Well Founded Relation
A well founded relation over set A will not have an innite descending
chain:
a
2
a
1
a
0
Examplie: The predecessor relation on N
0 2 . . . n
But the > relation on N is not.
Also, any reexive relation cannot be well-founded since we just have
. . . a a a
What about ? Yes. You cannot construct a set of all sets, so you cant
have S
2
S
1
S
0
.
Proper subexpression.
e

subexpression of e = e

e
is well founded.
To show that P(x) holds for all x A:
x A. (y x.P(y)) = P(x)
x A.P(x)
WF-Induction
Ordinary induction on naturals is WF-Induction where
A = N,
N
Since 0 is of
N
, then ordinary induction is an instance.
Strong induction depends on the <
N
.
Assume P(y) for all y < x, then show that P(x).
Why does this work?
Suppose that weve shown that for some a
0
, P(a
0
). Now, it must be
the case, that if were under the WF-Induction, that there exists some
a
1
a
0
such that P(a
1
), etc which means that we can construct an innite
descending chain where P(a
i
). But since is well founded, this is a
contradiction.
1
2 Structural Induction
When we prove things using the subexpression relation
Denition 1. e e

if e

is a proper subexpr of e
Theorem 1. Under CBVs e e

, and that e is well-formed (no free vari-


ables), then if e e

, then e

is also well formed.


Proof. Lets have
P(e) e

.e e

Fvs(e) = = Fvs(e

) =
We want to prove that e expr.P(e).
We can prove this on the subexpr relation on expressions, with a case anal-
ysis on e e

from middle exclusion


Recall that CBV has operational semantics
(x.e) v e {x/v}

e
1
e

1
e
1
e
2
e

1
e
2
L
e
2
e

2
v e
2
v e

2
R
L rule e = e
1
e
2
and e

= e

1
e
2
, also that Fvs(e) = = Fvs(e
1
)
Fvs(e
2
) = both those are also null.
By the IH on the expression e
1
e
1
e
2
, we have that e
1
e

1
=
Fvs(e
1
) = Fvs(e

1
) = , which immediately gives that
Fvs(e

) = Fvs(e

1
) Fvs(e
2
) =
which shows the case
e = (x.e) v and e

= e {v/x}, then it must mean that Fvs(x.e) =


and Fvs(v) = . So that Fvs(e) {x}.
Were stuck, so use the following lemma
Lemma 1 (Substitution).
Fvs(v) = = Fvs(e {v/x}) = Fvs {x}
Proof. By structural induction on e.
e ::= x | x.e | e
1
e
2
Lets do a case analysis on the possible expressions
e = x Then Fvs(e {v/x}) = Fvs(v), but weve already assumed that
Fvs(v) = = Fvs(x) {x}, which shows the case.
e = y Then Fvs(y) = {y} = Fvs(y) {x}, which shows the case.
2
e = e
0
e
1
Then we have that
Fvs(e {v/x}) = Fvs(e
0
{v/x}) Fvs(e
1
{v/x})
By ih on e
0
e and on e
1
e, we have that Fvs(e
0
{.}) =
Fvs(e
0
) {x} and vice versa for e
1
. So their union is just the
same as Fvs(Fvs(e
0
)Fvs(e
1
)){x}) = Fvs(e
0
e
1
){x}, which
shows the case.
e = x.e
Fvs(e {v/x}) = Fvs(e) = Fvs(e) {x}
e = y.e

By well-formedness, we have that y / Fvs(v), so


Fvs(e

{v/x}) = Fvs(y.e

{v/x})) = Fvs(e

{v/x}) {y}
Now, since e

e, then we know that Fvs(e

{v/x}) = Fvs(e

)
{x}
So the above just becomes
Fvs(e

{v/x}) y = Fvs(e

) {x} {y} = Fvs(y.e

) {x}
which shows the case.
From Lemma 1, we have that Fvs(e

) {x} {x} = , so Fvs(e

) =
.
3 Command Equivalence of Imp
Theorem 2.
c,

c,


skip,

Proof. The can be proven by structural induction on c.


The can be proven by induction on the derivation of c,

.
Now for an inductively dened set A, x A has derivation
D =
axiom
x
1
.
.
.
axiom
x
2
.
.
.
x
3
So we can form a well-founded relation from the niteness of D that
D

D if D

is a subderivation of D. So induction on the derivation


of a proof means that if weve proven the case for all subderivation
D

D, then we can show that D.


By cases, well look at the last step on the derivation of c,

.
Skip Here, skip, , then its trivial that
skip,

skip,
x:=a,c
1
; c
2
,if Exercise
while Suppose that we do the case where
c = while b do c

and that
b, False
Lemma 2.
b, t = b,

t,
by structural induction
Now

while b do c

if b then c; while b do c

else skip,

which


if False then c; while b do c

else skip,

Lemma 3. if b,

t, then

if b then c; while b do c

else skip,

if False then c; while b do c

else skip,

While, True We have a rule


D =
b, True c,

while b do c,

while b do c,

Now, the c,

and the while b do c,

are subderivations
of D, so we can apply the induction hypothesis will give that
c,


skip,

while b do c,


skip,

which can be stitched into the above two lemmas to conclude the proof.
4
CS 6110: Feb 8
Lee Gao
February 8, 2013
1 Evaluation Contexts
We have the following types of rules
Reduction rules (like )
Structural congruence rules (like L and R)
So with larger languages, we might get large sets of congruence rules thats
messy. We can solve this problem by introducing evaluation contexts. Its
basically a term with a hole [] in it, but it can only be located where a
reduction may happen. So for CBV, the following is a valid context
((x.x) []) (y.y y)
unfortunately,
(x.[]) (y.y)
we dont reduce the [] next, but rather that application rst, so this isnt
an evaluation context.
We can write a grammar inductively:
E ::= [] | E e | v E
Where E[e] is E with the hole plugged in by e We can introduce a structural
congruence rule
e e

E[e] E[e

]
Context
1.1 CBN
Lets dene the same beta rule
(x.e) e

/x

with the contexts
E ::= [] | E e
and the same structural congruence.
1
1.2 Observational Equivalence
We have contexts that denes observations that can be made of the pro-
grams. When we talk about equivalence, we talk about that with respect to
some observations. For lambda calculus
C ::= [] | C e | e C | x.C
so we can plug in anywhere, not only where we can perform a reduction.
So two expressions e
1
e
2
if
C[e
1
] C[e
2
]
Theorem 1 (Observational Equivalence). C[e
1
] C[e
2
] implies that
e
1
e
2
Proof. SUppose that we have C[e
1
] v
1
and C[e
2
] v
2
, and v
1
= v
2
. The
idea is that we can construct another context C

such that
C

[v
1
]
but
C

[v
2
]
then there exists a context C

such that the two do not have the same


behavior convergence-wise. So C

[C[]] is a context evidence that e


1
e
2
2 Semantics by translation
So far weve only been talking about operational semantics, which says how
to evaluate on some perfect and abstract machine. This is basically telling
us how we build an interpreter.
There are two other styles
Translation: you convert the program to a better-understood repre-
sentation.
Denotational semantics we translate it into mathematical expres-
sion
Denitional translation we target another language
Axiomatic Semantics: what can be proven about the execution (Pre-
Post conditional hoare logic)
Lets talk about translation. The key idea is a concept of a meaning function,
and we use some kind of a semantic bracket e where e is the argument.
Occasionally, well give them names to make it clear which translation were
talking about. So for example, Ce or Ae. Some times e
CBV
2
Anyways, it takes in a source language expression and produces a target
language expression. So
: source target
2.1 Encoding CBN in CBV
Lets dene a semantic function : Cbn Cbv. We want to defer
evaluation by wrapping them up in .
e
0
e
1
= e
0
(z.e
1
)
x.e = x.e
x = x (z.z)
where z is fresh.
Heres an example. Suppose that
If xyz.x y z
so
If = xyz.x y z
= xyz.x y (w.z I)
What does it mean for a translation to be correct? Or, how do we know
that we have an adequate translation?
Adequacy: the source and the target languages agree on evaluation. So if
we have a source item e that

to v. Then
e

target
Therefore, we want, using some observational equivalence relation, that v


v.
So we have two properties: soundness
Theorem 2 (Soundness).
e

= v.e

v v v

and completeness
Theorem 3 (Completeness).
e

v = v

.e

v
Both soundness and completeness gives adequacy.
Theres a stronger notion
Theorem 4 (Full Abstraction).
e
1
e
2
e
1
e
2

3
CS 6110: Feb 11
Lee Gao
February 11, 2013
Were gonna analyze a scheme-like language with
rst-class functions
data structures
primitives
CBV
not statically typed
So the language looks like
e ::= n | True | False | null | x | x
n
.e | e
0
e
n
| let x = e
1
in e
2
| if e
0
then e
1
else e
2
| e
1
e
2
| (e
1
, e
2
)
let(x, y) = e
1
in e
2
| letrec x = y
n
.e ine

v ::= n | True | False | null | (v


1
, v
2
) | x.e
E ::= [] | E e | v
0
v E e | let x = E in e | if E then e
1
else e
2
| E e | v E | (E, e) | (v, E) | let(x, y) = E in e
Reduction rules: small step
e e

E[e] E[e

]
Context
(x
n
.e) v
n
e {v/x}

n = n
1
n
2
n
1
n
2
n
Arithmetic
let x = v in e e {v/x}
Let
x = y
let(x, y) = (v
1
, v
2
) in e e {v
1
/x} v
2
/y
LetPair
if True then e
1
else e
2
e
1
IfTrue
1
Can we reduce this to lambda calculus? Lets call our language uMl for
untyped ML. Now, we can dene a translation function that translates
from uMl to . Make sure that the things on the right hand side on a
subterm where sub is dened by some well-founded relation .
x
n
.e =

x.e
e
0
e
n
= e
0


e
x = x
n = n
True =

True I
False =

False I
null = x.x
let x = e
1
in e
2
= (x.e
2
) e
1

if e
0
then e
1
else e
2
= e
0
(z.e
1
) (z.e
2
)
(e
1
, e
2
) =

PAIR e
1
e
2

let(x, y) = e
1
in e
2
= (p. (x.y.e
2
) (L p) (R p)) e
1

Unfortunately, this is not sound because we can translate null null


into a valid term with normal form, but which has no normal form in
uML. This is a runtime type error to apply null as if its a function. The
technical term for this is that this is a stuck conguration. This is an unsafe
language/not strongly typed.
Denition 1 (Strong Typing). A language is strongly typed if there are no
stuck congurations.
Equivalently, programs do not get stuck ( ) if they are well-formed.
On the other hand, static typing means that the compiler is going to assign
types to terms at compile time.
Examples of strongly typed languages
OCaml, SML
Java

Scheme
Javascript
Examples of statically typed languages
C
C++
2
Forth
PS
1 Fixing uML
One idea is to add transitions from all stuck terms to the error term. But
we need to dene this for all error terms, which may be tedious. We dene
a set of stuck redexes:
s ::= v
0
= (x
n
.e) v
n
| let(x, y) = (v = (v
1
, v
2
)) in e
and the new transitions basically say
E[s] error
Stuck
Lemma 1 (Progress). If e is well formed program and e

, then either
there exists some e

such that e

or e

is a value, or e

= error.
Now, a second way to x uML is to add a type system. A type system will
strengthen the notion of well-formed (if our type system is sound) so that
well-formed terms do not get stuck.
Going back to the rst idea, how do we dene the previous transition? The
idea is to tag values with their runtime types. We can represent null in
the source language as a pair (1, null), so we call this runtime type tagged
variant uML.
uML uML
null ((1,null)
true (2,true)
false (2,false)
n (3,n)
(v,v) (4, (v
1
, v
2
))
x
n
.e (5, (n,. . . ))
So were going to do a translation
uML uML


So
n = (3, n) = INT n where INT = x.(e, x)
t = BOOL t
null = NULL null
(e
1
, e
2
) = PAIR(e
1
, e
2
)
= FUN (n, )
error = (0, 0)
e
0
e
n
= let(t
0
, p
0
) = e
0
in if t
0
= 5 (let(y, f) = p
0
in y = n) then f

e else (0, 0)
3
So what were doing is that were always going to error unless everythings
good. However, this has an overhead in both stu and in the time, since
we need to check the well-typedness property. Therefore, its nice to have a
type system to make sure that we dont get stuck!
4
CS 6110: Feb 13
Lee Gao
February 13, 2013
(Names and Scope)
Suppose we have the program
1 l et rec e v i l f 1 f 2 n =
2 l et f ( x) = n + 10 in
3 i f n = 1 then f ( 0) + f 1 ( 0) + f 2 ( 0)
4 el se e v i l f f 1 ( n1)
5 in l et dummy = fun x > 1000 in
6 e v i l dummy dummy 3
what does this compute?
Theres two ideas:
static/lexical scoping: variable is bound to the closest enclosing bind-
ing in lex.
dynamic scoping: variable bound to the most recent active binding.
(early Lisp, APL, T
E
X, Perl, early Python, PostScript, . . .
So under static scoping, we have the result to be 36, but 33 in dynamic
scoping.
If you have a dynamically scoped language, the free variables are bound by
the caller. So for example, if we have a free variable x and we import it
into an environment that has a binding to x, it may shadow the expected
behavior of x. Its unpredictable but cool.
Dynamic scoping also suers on the performance side. Its more dicult to
gure out how the variables are supposed to be bound, so we need a certain
level of analysis to generalize the possible values of x.
1 Denitional Tranalsation
We need a naming environment : Var Value error. Lets start with
an empty environment
0
x.error. Our terms will have meaning in .
Well write this meaning as an argument to the translation
e

1
so that

: Term Env uML


but that the image is restricted to the closed terms.
1.1 Static Scoping
on

= n
ox

= x where x is some encoding of var


oe
1
e
2

= oe
1

oe
2

oe
0
e
1

= oe
0

oe
1

ox.e

= y.oe
[ xy]
Unfortunately, this may not be closed as is Fvs, so we use closure conver-
sion for
(x

= x
(x.e

, y.

.(e
[ xy]

(e
0
e
1

= let(

, f) = (e
0

in f (e
1

In general, closures and environments they point to cannot be stack allocated


since they must persist after function call, modern compiler uses escape
analysis to gure out which variables do not need to be heap allocated.
1.2 Dynamic Scoping
Tn

= n
Tx

= x where x is some encoding of var


Te
1
e
2

= Te
1

Te
2

Te
0
e
1

= Te
0

Te
1


Tx.e

= y.

.Te

[xy]
In dynamic scoping, its basically the same translation as static, but without
closures. The purpose closure is to save the static environment.
2 Operational Semantics
Well use the translation as a guide. Lets go with the semantics.
e, v
2
x, (x)
Var
x.e, (, x.e)
Lambda
e
0
, (

, x.e) e
1
, v
1
e,

[x v
1
] v
e
0
e
1
, v
App
2.1 Dynamic Scoping
x, (x)
Var
x.e, x.e
Lambda
e
0
, x.e e
1
, v
1
e, [x v
1
] v
e
0
e
1
, v
App
3 Observational Equivalence
Theorem 1 (Equivalence).
oe

e x Fvs(e).( x)/x = e
Proof. By structural induction on e. Cases:
e = x.
ox

= ( x) = x, which shows the case.


e
0
e
1
oe
0
e
1

= oe
0
oe
1
. By IH, we have that oe
0
= e
0
and also
that e
1
. So e
0
e
1
= (e
0
e
1
) , which shows the case.
x.e
ox.e

= y.oe
[ xy]
. By IH, we have that oe
[ xy]
= e [ x y] =
e x, y/ x. By expansion, this is just y. (x.e x) y. Lets
use an eta reduction to get x.e x = (x.e) , which shows the
case.
3
CS 6110: Feb 15
Lee Gao
February 15, 2013
What is the let rec construct?
letrec y
1
= x
1
.e
1
, y
2
= x
2
.e
2
, . . . in e

OS: we substitute the entire let rec in.


letrec

y = .e xin e

{letrec . . . in x.e
1
/y
1
} {letrec . . . in x.e
n
/y
n
}
letrec
As a translation using naming environments: target language is still the
closed uML.
Lets imagine that we have a Merge function that merges two ,

.
letrec

y = x.e in e

= e

Merge


Now, we want

= Y

.x. if x = y
1
then x.e
1

else if x = y
2
then x.e
2

else . . .
If youre building a compiler for this language, then instead of using the Y
combinator, you use mutations and back patching in order to remedy the
self-referencing issue in the environment table.
So far, the naming schemes weve used so far are hierarchical. (Theres a
notion of nesting scopes). What if we want non-hierarchical names?
1 Non-hierarchical names
We want to build separate modules that can exploit public names. You can
reason about correctness and other properties of modules in isolation.
How do we export names from one module to another?
One idea is to have a huge global namespace (such as in C). Problematic
because there could be collisions in names. Works as long as libraries arent
too big.
1
Another idea is to add module mechanisms explicitly, so we can group related
functions together and export a set of names that form the interface from
which other modules can talk about and communicate to.
Construct modules:
1 module (x
1
= e
1
, . . . , x
n
= e
n
)
Selector e
m
.x to get the x outside of module m dened by e
m
.
Import/Open/With to bring all of the identiers into scope from some mod-
ule dened as e
m
.
1 i mport e
m
in e

However, in uML, it is a term/rst class value. A rst class value is just as


normal as any other terms. What can we do?
bind to variables
pass as arguments
return as a result
In ML, Java, and most other languages, modules are more second class. This
is done to ensure that all module level computations are done at compile
or link time. In ML, you are only allowed to pass modules to functors,
which are also second class.
Were going to translate uML+modules to uML that is closed. Side: we
can interpret the as were translating it into a lambda that rst takes in
an environment and passes it around in between themselves.
Mx

= x
A module is really similar to a naming environment , so lets just represent
these as such.
Me
m
.x

= Me
m

x
Mimport e
m
in e

= Me

Merge Me
m

Mmodule {

x = e}

= x. if x = x
1
then Me
1

else . . .
Unfortunately, this semantics will not allow any of the e
i
to be dened in
terms of the internals, so we need to merge the environments again with
itself.
Mmodule {

x = e}

= Y

.x. if x = x
1
then Me
1

else . . .
This allows us to write
1 l et m = module ( x = y + 1 ,
2 y = x + 1) in
3 m. x
2
Since the xed point of m has no normal form x.. How do we avoid
this? Solutions:
on allow bindings to values
allow some expressions that arent values, but only allow references to
earlier variables. So we build and re-pass in the approximate naming
environment as we go.
break the xed point (so the solution isnt a xed point to m)
allow divergence .
OCaml is nice in that all recursive denitions are explicitly dened in let
rec, so you know where that xed point combinator is coming in. Java takes
a xed point over the entire class hierarchy (including the standard library).
This is sometimes known as open-recursion.
3
CS 6110: Feb 18
Lee Gao
February 18, 2013
States: (refs, mutable variables)
A state is this idea of a dynamic binding from identities to values. Moreover,
these bindings can change over time.
It matches our mental model of how the world is. It might be a lie, but its
a convenient lie
But its harder to reason about the program and its nonlocal (you dont
know how far the eects of your variable will go). This way of reasoning
that all states are equal is that it is a misleading performance model.
1 Stateful uML
Let uML! be the stateful version of uML. We get
e ::= uML [ ref e [!e [ e
1
:= e
2
[ l
where l is a symbolic variable for locations (think of them as memory ad-
dresses). We need this within the operational semantics.
v ::= v(uML) [ l
1 l et x = r e f 1 in
2 l et y = x in
3 l et z = ( x: =2) in
4 ! y
x
2
y
1.1 Small Step Operational Semantics
Lets augment our conguration to be e, where : location value. Well
lift all uML rules to corresponding rules
e,

1
New reductions
l / dom()

= [l v]
ref v, l,

Ref
v = (l)
!l, v,
Bang

= [l v]
l := v, null,

Set
E ::= [ ref E [!E [ E := e [ l := E
We only allow congurations where all locations l e are in dom() This is
the preservation of well-formedness of with respect to e. Next, we need to
lift the old context rule
e, e

E[e], E[e

],

Context
2 State-passing translation
For uML! uML. Assume that we have an implementation of as a term
in the target language uML such that we have
[l v] Update l v
fresh l Malloc
(l) Lookup l
Empty
Translation o

: uML uML
oe
,

(v,

)
Lets start
on

= (n, )
ox

= ((x), )
oif e
0
then e
1
else e
2

= let(b,

) = oe
0

in if b then oe
1

else oe
2

olet x = e
1
in e
2

= let(y,

) = oe
1

in oe
2

[xy]

oe
0
e
1

= let(f,

) = oe
0

in let(v,

) = oe
1

in f v

So the translation of a function must also take in the as well.


ox.e

= y

.oe
[xy]

2
3 Mutable Variables
There are no refs, but there will be pointers, and that variables are inherently
mutable. LValues vs RValues.
e ::= uML [ e
1
= e
2
[ e [ &e [ e
1
; e
2
Lets have a translation for LValues
/e

= location of e
and
!e

= value of e
so as before, but : var locations
!n

= (n, )
/x

= ((x), )
!e

= let(l,

) = /x

in

(l) but only when /e is dened


!e
1
= e
2

= let(l,

) = /e
1

in let(v,

) = !e
2

in (v,

[l v]
/e

= !e

!&e

= /e

so we should be able to write *&*&x = 2


!x.e

= y.

. let l = Malloc in !e
[xl][ly]
!e
0
e
1

= Same
If we want to allow pass by reference that updates the location outside of
the scope of that lambda, we can model this as, using the notion of a pass
by reference function
!
R
x.e

= l

.!e
[xl][ly]
and we need to update the machinery of applications
!rcall e
0
e
1

= let(f,

) = !e
0

in let(l,

) = /e
1

in f l

3
CS 6110: Feb 22
Lee Gao
February 22, 2013
CPS Continuation passing style.
We can use this style of writing code to give errors and exceptions. So we
need to be able to transfer ow that doesnt ow local control ow. But
continuation lets us dene control ow explicitly.
We dened some functions to tag things.
BOOL : t.(2, t)
so that
not e = let(t, b) = e in if t = 2 then BOOL NOT b else ERROR
itd be neat to factor out the boilerplate code to check if tags are right. We
would want a function that checks tags and then returns the untagged value
if the tag is correct.
If the error is wrong, then in CPS, once we transfer the control, just never
come back. So in CPS, a function becomes a continuations transformer, so
that it takes in one continuation and turns it into another continuation.
CHECKBOOL = k.v. let(t, b) = v in if t = 2 then k v else halt ERROR
So in CPS translation
not e
k
= e
CHECKBOOL (b.k BOOL(NOT b))
if e
0
then e
1
else e
2

k
= e
0

CHECKBOOL (b. if b then e


1

k
else e
2

k
)
e

e
n

k
= e
0

CHECKFUN n

f.f e
1

f
1
.e
2

f
2
....f
n
.f k v
1
...

x
n
.e
k
= k

FUN n k

.x.e
k

This might extend to exceptions.


1 Exceptions
Augment terms with
e ::= uML | raise s e | try e
1
catch (s x) e
1
this is a dynamic binding of try-catch. The most recently invoked try that
hasnt caught. You need an environment for exceptions. Dene a handler
environment that maps from exception names to continuations.
To do this, we have
e
k,h
where k is the continuation and h is the handeler environment. Functions
in target should look like
k h x. . . .
x
k,h
= k x
x.e
k,h
= k

x.e
k

,h

e
0
e
1
= e
0
(f.e
1
(v
1
. . . . f k h v))
You can think of exceptions as dynamically scoped variables bound to con-
tinuations.
Now, lets move on to the translational semantics of raise and catch.
raise s e
k,h
= e
h s,h
so raise inside raise means that the rst raise didnt happen
try e
1
catch (s, x) e
k,h
= e
1
k (h[x x.e
2
k h])
So far, weve looked at termination semantics. Theres another idea of re-
sumption semantics. If you have an expression that hits an unusual excep-
tion, can we dene a handler that xes it?
2 Resumption Semantics
Were going to have a new type of exception interrupt.
e ::= | interrupt s e | try e
1
handle (s, x) e
2
But our handler environment will take exception names, map them to func-
tions, then go back to the original continuation.
interrupt s e
k,h
= e (v.h s k h v)
try e
1
handle (s, x) e
2

k.h
= e
1
k

h[s k

x.e
2
k

h(or h

)]

2
CS 6110: Feb 22
Lee Gao
March 13, 2013
Theorem 1.

n
e
nm
=

nm
e
nm
=

k
e
kk
1 What are the operations on these cont functions
Compose It takes in a pair [D E] [E F] [D F], and it is
dened as
p [D E] [E F].x D.(
2
p) ((
1
p) x)
Curry : [D E F] [D [E F]] and symmetrically uncurrying.
Apply : [D E] D E
Fix : [[D D] D]
g [D D].

n
g
n
() =

n
g
n

()
2 Denotational Semantics for a language with rec
Lets dene a language Rec which is just rec functions.
p ::= let d in e
d ::=

f
i
(x
i
, , x
a
i
) = e
i
e ::= n | x | e
1
e
1
| let x = e
1
in e
2
| if e
0
then e
1
else e
2
| f
i
(e
1
, , e
a
i
)
Lets come up with a denotational semantics. We need a variable environ-
ment : V ar Z. We also need a function environment
: (Z
a
1
Result) (Z
a
1
Result)
so that

i
= f
i
1
(denotationally equivalent). Now, our denotational translation:
e : Result
but since we can have general ad-hoc recursion, we need to lift Z for Result.
So
Result = Z

1 n = ]n_
2 x = ] x_
3 e
1
e
2
= l et v
1
: Z = e
1
in
4 l et v
2
: Z = e
2
in
5 ]v
1
v
2
_
6 = e
1

e
2

7 if e
0
then e
1
else e
2
= l et b : Z = e
0
=
8 i f b > 0 then
9 e
1

10 el se
11 e
2

12 let x = e
1
in e
2
= l et v : Z = e
1
in e
2
[x v]
13 f
i
(e
1
) = l et v
1
: Z = e
1
in
14 l et v
2
: Z = e
2
in
15
.
.
.
16 v
a
i
: Z = e
a
i
in
17 (
i
) v
1
, , v
a
i
)
18 let d in e = e Td
So of course, we now need to dene the same thing for D.
Df
1
( ) = e
1
, =
1 Tf
1
( ) = e
1
, f
n
( ) = e
n
= x . (p
1
: Z
a
1
.e
1
|x
1

1
p
1
. . . ,
2
.
.
.
3 = p
n
: Z
a
n
.e
n
|x
1

1
p
n
. . . )
but how do we get the in there if its out there. Take a least upper bound
to resolve this. Is this function F continuous? Yes. But is our function
environment a pointed CPO?
Since the function environment is a tuple, it will be pointed if Z
a
i
Result
are pointed, but this must produce bottom every where, so as long the
codomain Result is pointed, were okay. But since Result = Z

, then
were good.
3 Call By Name Rec
Here, we lazily evaluate variables, so we can bind to divergent terms as long
as they do not get evaluated. So our environment is still
: V ar Z

2
but functions can now expect divergent terms, so
: Z
a
z


so we just need to chainge
1 x = (x)
2 f
i
( ) = (
i
) e
1
, )
3
CS 6110: April 1
Lee Gao
April 1, 2013
1 Recap: SOS
e
0
e

0
e
0
e
1
e

0
e
1
L
e
1
e

1
v
0
e
1
v
0
e

1
R
(x : .e) v e {v/x}

with typing judgments


, x : x :
e
0
:

e
1
:
e
0
e
1
:
, x : e :

x : .e :

2 Soundness
Soundness, if we can derive a typing judgment, then e shouldnt get stuck.
Theorem 1 (Soundness).
e : e

= e

V al e

.e

To prove this, we need preservation and progress.


2.1 Preservation
Also known as subject reduction.
Lemma 1 (Preservation).
e : e e

= e

:
2.2 Progress
Lemma 2 (Progress).
e : = e val e

.e e

So intuitively, were going to have a chain of reductions


e e
1
e
2
e

where each of the above has type by preservation, but then e

will either
be a value or can step by progress, which shows soundness.
1
3 Proofs
Lemma 3 (Preservation).
e : e e

= e

:
Proof. We want to use induction on the derivation of e : , using the
immediate subderivation relation which is trivially well-founded. Well
do a case analysis on the last rule used in the derivation of e e

.
L Here, e = e
0
e
1
, e

= e

0
e
1
, and we get e
0
e

0
. The only derivation
matching this is just e
0
e
1
: , so we get the immediate subderiva-
tions e
0
:

and e
1
:

. But since these are e : ,


we can apply IH to get e

0
:

, this together from the second


immediate subderivation of e : , namely e
1
:

, we can then
construct the derivation taht e

0
e
1
: , which shows the case.
R Without loss of generality, same as the L case.
Here, we have e = (x :

.e
0
) v and e

= e
0
{v/x}. We have no premises,
and the only derivation that we can apply for e : is the application
rule, so we have x :

.e
0
:

and that v :

. Inverting the
derivation of the , we also get that x :

e
0
: . Next, were going
to need a substitution lemma to push this proof any further. See
below rst, then come back. By discharging substitution, we show the
case and conclude the proof.
Lemma 4 (Substitution).
, x : e : v :

= e {v/x} :
Proof. We will show this by induction on the structure of e with a case
analysis on e.
n Here, e = b, which trivially hold.
Var 1 Here, e = y = x, so here (y) = (, x :

)(y), so its invariant.


Var 2 Here, e = x, so e {v/x} = v. But we have , x :

v : and v :

by weakening (show) gives that =

. Finally, the second premise


gives v :

= , which shows the case.


App e = e
0
e
1
, so e {v/x} = e
0
{v/x} e
1
{v/x}. Applying the induction
hypothesis on the immediate subexpressions with the same v-premise
to get , e
0
{v/x} :
0
, and so forth.
Abs Here, we need to break this into a few cases.
2
1. e = x :

.e
2
, so e {v/x} = e, so we have the case trivially
already.
2. e = y :

.e
2
, y = x, but since we have a typing derivation of v,
we also have y / Fvs(v), so e {v/x} = y :

.e
2
{v/x}. Now, we
have the derivation
, x :

, y :

e :
2
, x :

e {v/x} : =


2
Abs
but by IH, we get , y :

e
2
{v/x} :
2
. From this, we can
construct the derivation for y :

.e
2
{v/x} = e {v/x} :


2
= , which shows the case and concludes the proof.
Lemma 5 (Progress).
e : = e val e

.e e

Proof. By structural induction on e with a case analysis.


n Here, e = b, which is a value, so were done trivially.
x Here, e = x, but theres no derivation for x : , so vacuously true.
Abs Here, e = y : .e

, but this is a value, so were done trivially.


App Here, e = e
0
e
1
. Obviously, e / val, so we need to show that e

.e
e

. We have e
0
e
1
: , so we get e
0
:
1
and e
1
:
1
, so by IH, we
have that either e
0
is a value or e
0
e

0
, and same for e
1
. Lets do a
case analysis here.
If both are values, then we just apply (We need a normal-form lemma
here), which we can show by inspection of the derivation of on the
structure of v.
If e
0
is a value, but e
1
is not, then we just apply the R rule
Otherwise, we just apply the L rule.
Hence showing the case, and concludes the proof.
3
CS 6110: April 3
Lee Gao
April 3, 2013
1 Subtyping
Products generalize into records and sums generalize into variants.
Records:
::= {x
1
:
1
, , x
n
:
n
}
1

n
and we can construct these as
e ::= | {x
1
= e
1
, } | e.x
where the rst is analogous to construction and the second to projection.
We extend the normal form to contain value records. Our SOS contains
{

x = v} .x
i
v
i
and extending the typing judgment to contain the rule
e
i
:
i
{

x
i
= e
i
} : {}
and for projections
{

x : }
e.x
i
:
i
We can do a similar kind of trick for sums to get variants:
::= | [

x
i
:
i
]
and
e ::= | in
x
(e) | case e of in
x
i
(y
i
) e
i

so
(case in
x
i
(v) of in
x
(y) e) e
i
{v/y
i
}
and extending the typing judgment to
e :
i
in
x
i
(e) : [

x
i
:
i
]
e : [

x
i
:
i
] , y
i
:
i
e
i
:
case e of

in
x
(y) e :
These are very similar to the concept datatypes in Ml.
Suppose we want to write something like
1
1 cl ass Poi nt {
2 i nt x , y ;
3 void draw( Symbol s ) ;
4 }
this is really similar to the record type
{x : int, y : int, draw : Symbol 1}
We can also do subtyping in java.
1 cl ass Col oredPoi nt extends Poi nt {
2 Col or c ;
3 }
4 Poi nt p = new Col oredPoi nt ( )
this is really similar to
{x : int, y : int, draw : Symbol 1, c : Color}
but in our sltc so far, we cannot just stick ColoredPoint instance into some-
thing expecting a Point. We can dene a kind of equivalence/ordering as
subtyping. Dene an ordering so that ColoredPoint Point.
Denition 1.

1

2
to mean that
1
can be used where
2
is expected.
1.1 Interpretations
1. so that
1
is a
2
, so that semantically (or denotationally), the class
T
1
T
2
.
2. you can convert/coerce
1
into a
2
(an extension). We can dene this
coercion function : (
1

2
)
1

2
Interpretation two allows us to translate a subtyping language into a simply
typed language, as long as we dene .
1.2 (Sub)Typing
e :

e :

Subsumption
this rule is not syntax directed, (like the weakening rule in hoare logic).
Furthermore, the subderivation relation is no longer well-founded.
Now, we need to have some subtyping rule. Well dene them structurally.

1

2

2

3

1

3
Trans
so that is already a preorder.
Now, lets dene how these rules aect other types.
2
1.3 Products

1

2

2
Prod
Product subtyping is covariant wrt components.
Another way of seeing this is that we can actually dene a coercion function
so that
(
1

2
) = p :
1

2
.((
1

1
)(
1
p), (
1

1
)(
2
p))
1.4 Sums
Sums are also covariant, so the coercion function is still covariant.
(
1
+
2

1
+

2
) = s :
1
+
2
.case s of x
1
:
1
in((
1

1
)x
1
) |
1.5 Supertype
The universal super type is 1, so we can always say that 1. With
coercion
( 1) = x : .()
1.6 Subtype
Dene 0 (or void) with no instances and corresponding to . It is the of
the relation. For example, errors or has type 0.
1.7 Functions
Eiel wanted to do this covariantly, but we want to be able to coerce

1
into

1
, so the judgment is contravariant.
1.8 Records
Methods in Java are covariant only in return type. (The argument type is
on the class name)
covariance
{x
1
:
1
, , x
n
:
n
}

x
1
:

1
, , x
n
:

n
depth
m n
{x
1
:
1
, , x
n
:
n
} {x
1
:
1
, , x
n
:
m
}
width
what about permutation subtyping? We can actually order the eld labels
rst, but we can assume this for our system.
3
1.9 Variants
covariance
[x : ] [x :

]
depth
n m
[x :
n
] [x :
m
]
width
notice how the width rules ip between variants and records.
1.10 References
::= | ref
and
e ::= |!e | e
1
:= e
2
| ref e
with natural rules.
Subtyping rules
invariance

1
ref
2
ref
so no refs.
4
CS 6110: April 10
Lee Gao
April 10, 2013
1 Type Inference
Also known as type reconstruction. The basic notion is to stick in type
variables for unknown types, which gives a system of type equations. This
lets us write the typing rules in a dierent way.
, x : T
x
e :
x.e : T
x

Lam
and
e
0
:
0
e
1
:
1

0
=
1
T
2
e
0
e
1
: T
2
App
so type checking gives a system of equations. The main thing dierent here
is that theres a constraint as a side-condition of each inference rule.
Suppose that we have
f : T
f
f : T
f
1 : int T
f
= int T
2
f : T
f
, x : T
x
f 1 : T
2
App
f.x.f 1 :
0
y.y :
( f.x.f 1)(y.y)
App
this generates the following constraints
T
f
= int T
2
T
f
T
x
T
2
= (T
y
T
y
) T
1
which says that by direct substitution
(int T
2
) T
x
T
2
= (T
y
T
y
) T
1
so here, (T
y
T
y
) = (int T
2
) = T
y
= T
2
= int and T
1
= T
x
int.
What this says is that T
x
is unconstrained.
1
1.1 Unication
This idea dates back to 1965 (Robinson). In general, we have two type
expressions, which stands at equivalence:
1
=
2
. Our goal is to nd the
weakest substitution S such that S(
1
) = S(
2
).
Suppose we have

T
1

T
1 bool
and

+
T
3 int
T
2
So we can say that S
2
S
1
(S
2
is weaker) if there exists som non-trivial S
3
such that S
1
= S
3
S
2
.
Suppose we have a set of equations
E =

1
=

1
,
2
=

2
,

and were trying to nd the weakest/laziest substitution. Dene unify(E)


as
unify() =
unify(B = B, E) = unify(E)
unify(T = T, E) = unify(E)
unify(
1

2
=
3

4
, E) = unify(
1
=
3
,
2
=
4
, E)
unify(T = , E) = unify(E {/T}) (T )
it had better be the case that T / Fvs().
What is the ordering relation on E such that E
1
E
2
is well-founded?
Note that in the substitution case, the number of unsolved variables go
down, whereas in the rest, the height goes down. So
Well say E
1
E
2
if Fvs(E
1
) Fvs(E
2
) or if they have the same set of
fvs, then the size of E
1
is strictly less than E
2
.
So how do we use this algorithm?
1.2 Hindley-Milner Algorithm W
Here, we just apply constraints to unify as encountered.
2
So, if we just ask for the type of
x.x : T
x
T
x
Lam
but now this is polymorphic, so T
x
= or that theres a type schema such
that
T
x
= .
Furthermore, how quick is this algorithm? It is doubly exponential. How-
ever, theyre wrong.
1.2.1 What ever PLT should know
So let f
0
(x) = x and f
1
(x) = if b then f
0
else x f
0
, and so on, so
f
n
(x) = if b then f
n1
else x f
n1
So here, f
0
: , and f
1
: T
0
T
0
, so the types may be expanding
exponentially, so the substitution step will take some type going over these
possibly exponential types.
But if we dont need to output the types, we can do this in poly time.
Idea: types are directed acyclic graphs.
3
CS 6110: April 22 Abstract Interpretation
Lee Gao
April 22, 2013
1 Monads
We have
D M(D)
with the operations
1 uni t ([] , r et ur n ) : D M(D)
2 bi nd ( , >>=) : (D M(E)) (M(D) M(E))
With semantics
(skip = [] : M() =

(x := a = [[x /a]]
(if b then c
1
else c
2
= if Bb then (c else (c
2

(c
1
; c
2
= (c
2

((c
1
)
(while b do c = xw : M. . if Bb then w

((c) else []
Monads capture abstract computational eects.

is the strictness monad,


which handles divergence. We dene
[] = |
f

() =
f

(|) = f()
The CPS monad:
M = ( ans) ans
so we will build the monad as
[] = k ans.k
and binding
f

(m) : M ( ans) ans


1
and m ( ans) ans. We want to get out a M, so f : M M.
So M is the domain of continuations, and we want a continuation
f

(m) = k ans.m( .f k)
we can now apply the lift monad onto this to get the correct semantics.
(skip = [] = k.k
(c
1
; c
2
= (c
2

((c
1
) = k.((c
1
)((c
2

l
k)
2 Abstract Interpretation
We want to lift computation on onto a coarser domain M on which we
can do analysis. Then, were going to run the program on M rather than
on , and we will tweak the semantics to only deal with M.
Suppose that M < and
1
,
2
both maps to the same m M, but these
are distinct, we might need to join domains.
Let
() = m M
and since we need a join ., we need M to be an upper lattice with a join
operation m
1
. m
2
.
This turns out to not be enough, we also want to have our program termi-
nate.
We will use a widening operator . so the idea is that
m
1
. m
2
_ m
1
m
2
furthermore,
m
1
_ m
1
m
2
_ m
1
m
2
m
3

this chain stabilizes at some nite n (converges).
Now, if M is nite height, we can just use the join as our widening operator.
The is the join/union of all = can be in any state, we dont know which.
Then lower is more precise.
2.1 Modeling this as monad
How do we lift from a state to this monadic domain?
M = M
and
[] = []
and
f

(
M
) =
M
2
and
f

(m) =

f() [ () = m
then
(c : M
but we dont want to work with states, so we can star it
(c

: M M
this is exactly what we want, it is called an abstract interpretation. But this
is going to be verrrry hard to compute. So instead, were going to dene
another translation called (

c which approximates (c

, in other words
(c

_ (c

(recall that higher up = less precise)


Image that we want to run programs, but we only care about the nega-
tive/nonnegativeness of x.

<

Dene the translation


(skip

m = ([]

)m =

m = m
because already has codomain M, and the
Theorem 1 (Final Unit).
[]

= id
Theorem 2 (Initial Unit).
f() = f

([])
Theorem 3 (Associativity).
(f

1
f
2
)

= f

1
f

2
tells us that []

= id.
Now, lets look at
(x := a = [[x /a]]
then
(x := a

<=

< if x < 0 = a < 0


if x < 0 = a 0
otherwise
3
and applying to top gives
(x := a

< if a < 0
if a 0
otherwise
and for an assignment with a dierent y ,= x
(y := a

m = m
and for
(c
1
; c
2

= (c
2

(c
2

but we want not bake associativity in the overapproximation, so it is just


dened as
(

c
1
; c
2
= (

c
2
(

c
1

and for if
(

if b then c
1
else c
2
<=

c
1
< x < 0 = b
(

c
2
< x < 0 = b

c
i
<
symmetrically for , so lets look at
(

if b then c
1
else c
2
= (

c
1
m
1
. (c
2
m
2
where
m
1
=

< b = x < 0
b = x 0
b = false
i dont know
Interesting case: While
(while b do c =

n
(F
n
())
then its starred version is just (from continuaty of star

n
(F
n
()

m)
We dont necessarily have an ordering on F
k
()

m, But, we can form an


overapproximation:
F()

m _ F
2
()

mF()

m _
which must stabilize, but is an overapproximation. Recall that the xed
point taken over a dataow equation is exactly this!
4
CS 6110: April 24
Lee Gao
April 24, 2013
1 Object Encodings
Objects are self-referential and has this special feature like inheritance. We
can translate this into using records.
Consider the java code
1 cl ass i n t s e t {
2 i nt val ue ;
3 i n t s e t l e f t , r i ght ;
4 i n t s e t uni on ( i n t s e t s ) { . . . }
5 bool cont ai ns ( i nt n) {
6 i f ( n == thi s . val ue ) {
7 return true ;
8 } el se i f ( n < thi s . val ue ) {
9 return thi s . l e f t != nul l && thi s . l e f t . cont ai ns ( n) ;
10 } el se
11 return thi s . r i ght != nul l && thi s . r i ght . cont ai ns ( n) ;
12 }
13 }
14 }
This is a recursive type obviously, so we can model objects as records over
some .
What about this? It turns out that this could reference a subclass or a
superclass. Need to do something special to allow this open recursion.
intset . ({value : int, left : , right : , union : , contains : int bool} + 1)
where we dene null = ().
For example, if we want to build a non-null record, then
fold rec this : l
inset
> inl
inset
{v = 0, left = inr (), right = ..., }
but
union s

: inset.
and
contains n : int. if n = this.v then True else if n < this.v then case this.l ofs : intset > (unfold s).contains n | () : 1 > False else
.
.
.
1
We have not added in the concept of encapsulation (protecting elds). We
want to extend this encoding to hide the eld members.
intset . ({private : {value : int, left : } , right : , union : , contains : int bool} + 1)
2 Existential Types
Let denote the record that holds the private information.
e ::= |
::= | . |
E ::= |
so the inset example now becomes
intset .. ({private : , right : , union : , contains : int bool} + 1)
Another interpretation of existentials, the operational one:
2.1 Operational Intuition
An existential type is just a pair of the that were hiding, and then the
rest of the type where we substitute the hidden type for . So think of them
as
[, v] : .
so hat
v : {/}
note that v is an instance of this existential, the itself isnt lled in.
New expressions
e ::= | [, e]
.
| let[, x] = e in e

where the elimination form basically take out the type and the value. Other
people will just call this pack and unpack.
Evaluation context
E ::= | [, E] | let[, x] = E in e

Typing rules:
; {/} : {/} .
; [, e]
.:.
TPack
, e : . , ; , x : e

: /
, let[, x] = e in e

:
TUnpack
2
Operational Semantics
let[, x] = [, v]
.
in e

{/, v/x}
Pack
2.2 Logical Correspondence
In curry howard correspondence, we get a 1-1 correspondence to the exis-
tentials.
TPack
{A/x} A : Prop
x.
TUnpack
x. , x : Prop,

2.3 Examples
1 l et p
1
= [int, {5, n : int.n = 1}]
.bool
in
2 l et [, x] = p
1
in (right x) (left x)
3
4 l et p
2
= [bool, (true, b : bool.b)]
.bool
in
5 l et (, x] = p
2
in (right x) (left x)
3

Potrebbero piacerti anche