Midterm & Concept Review CS 510, Fall 2002 David Walker

advertisement
Midterm & Concept Review
CS 510, Fall 2002
David Walker
Midterm
Most people did just fine



greater than 90 = exceptional
80-90 = good
less than 80 = need more work
Three main parts:



MaybeML: 35
Objects: 35
Imperative objects: 30
Type-directed Translations
What is a type-directed translation?
Type-directed Translations
What is a type-directed translation?

it is a function (a compiler) that takes a typing
derivation for a source-language expression and
produces a target-language expression



we can define type-directed translations using judgments:
(G |- e : t) ==> e’
e is a source term; e’ is a target term
we define the translation using inference rules. eg:
(G |- e1 : t1 -> t2) ==> e1’
(G |- e2 : t1) ==> e2’
------------------------------------------------------------------(G |- e1 e2 : t2) ==> e1’ e2’
Type-preserving Translations
When is a translation is typepreserving?
Type-preserving Translations
When is a translation is typepreserving?


If given a valid derivation, it produces a
well-typed target expression
We often prove a theorem like this:
 if (G |- e : t) ==> e’ then
Trans(G) |- e’ : Trans(t)
 where Trans(t) is a
type translation function
this is an
ordinary typing
judgment
in the target
language
Maybe ML

Syntax:
 t ::= Bool? | t1 ?-> t2
 e ::= x | true | false | null
| if e1 then e2 else e3
| if? e1 then e2 else e3
| fun f (x:t1) : t2 = e | e1 e2
MinML (unit,+,->,exn)

Syntax:
 t ::= unit | t1 + t2 | t1 -> t2
 e ::= x | () | e1; e2 | inl (t,e1) | inr (t,e2) | ...

Question:
 Define a type-directed, type-preserving
translation from MaybeML to MinML
Type Translation
What I expected:


Trans (Bool?) = unit + (unit + unit)
Trans (t1 ?-> t2) =
unit + (Trans(t1) + Trans(t2))
Another possibility:


Trans (Bool?) = unit + (unit + unit)
Trans (t1 ?-> t2) = t1 -> t2
Type Translation
Almost:


Trans (Bool?) = anyt
Trans (t1 ?-> t2) = anyt
where anyt =
unit + (unit + unit) + (anyt -> anyt)

what is wrong here?
Type Translation
Almost:


Trans (Bool?) = anyt
Trans (t1 ?-> t2) = anyt
where anyt =
unit + (unit + unit) + (anyt -> anyt)

what is wrong here? Need a recursive type:
 anyt = rec a. unit + (unit + unit) + (a -> a)
Term Translation
Mirrors the form of the static semantics
Uses judgments with the form:

(G |- e1 : t) ==> e1’
Invariant:

If (G |- e1 : t) ==> e1’ then
Trans(G) |- e1’ : Trans(t)
Key: e1’ must type check under
fully translated environment
Term Translation (no opt.)

Example:
--------------------------------------------------------------------------(G |- true : Bool?) ==> inr (Trans(Bool?), inl (unit + unit, ()))

Example:
(G |- e1 : t1 ?-> t2) ==> e1’
(G |- e2 : t1) ==> e2’
(x,y not in Dom(G))
--------------------------------------------------------------------------(G |- e1 e2 : t2) ==> case e1’ of
( inl (x) => fail
| inr (y) => y e2’)
Term Translation (no opt.)

Wrong (but it was pretty tricky, so don’t worry):
(G,f : t1 ?-> t2, x : t1 |- e : t2) ==> e’
-----------------------------------------------(G |- fun f (x : t1) : t2 = e ==>
inr (..., fun f (x : Trans(t1)) : Trans(t2) = e’)
What goes wrong?
Consider:
fun f (x : unit) : unit = f x

and its translation:
inr (..., fun f (x : unit) : unit =
case f of
( inl (y) => fail
this
is a function
| inr (z) => z x))

NOT a sum value
Term Translation (no opt.)


The point of doing a proof is to discover
mistakes!
Must prove result of trans has the right type:
------------------------------------------------------ (by IH)
G,f : T(t1) -> T(t2), x : T(t1) |- e’ : T(t2)
------------------------------------------------------------------ (fun)
Trans(G) |- fun f (x : T(t1)) : T(t2) = e’ : T(t1) -> T(t2)
------------------------------------------------------------------ (inr)
Trans(G) |- inr (..., ....) : unit + (T(t1) -> T(t2))
Term Translation (no opt.)

We can’t apply the induction hypothesis!
 (T(G) |- e : t) ==> e’ is necessary
not the translation of a function type (unit + T(t1) -> T(t2))
------------------------------------------------------ (by IH)
G,f : T(t1) -> T(t2), x : T(t1) |- e’ : T(t2)
------------------------------------------------------------------ (fun)
Trans(G) |- fun f (x : T(t1)) : T(t2) = e’ : T(t1) -> T(t2)
------------------------------------------------------------------ (inr)
Trans(G) |- inr (..., ....) : unit + (T(t1) -> T(t2))
Term Translation (no opt.)

How do we fix this?
 create something with type (unit + T(t1) -> T(t2)) to
use inside the function
 then bind that something to a variable f for use inside
e’
 our old translation gave us something with the type
T(t1) -> T(t2) ...
Term Translation (no opt.)

How do we fix this?
(G,f : t1 ?-> t2, x : t1 |- e : t2) ==> e’
-----------------------------------------------(G |- fun f (x : t1) : t2 = e ==>
inr (..., fun f (x : Trans(t1)) : Trans(t2) =
let f = inr (..., f) in e’)
where
let x = e1 in e2
is
((fun _ (x : ...) : ... = e2) e1)
A useful fact
A let expression is normally just
“syntactic sugar” for a function
application
let x = e1 in e2
is the same as
 (fn x => e2) e1

Optimization
Observation:


There are only a couple of null checks that
appear in our translation.
Can we really do substantially better?
Optimization
Observation:


There are only a couple of null checks that
appear in our translation.
Can we really do substantially better?
 YES!
 The expressions that result from the translation
have many, many, many null checks:

if true then if false then if true then ....
our translation inserts 3 unnecessary null checks!
Some Possibilities
Some people defined a few special-case
rules:

Detect cases where values are directly
elimiated and avoid null checks:
 (fun f (x:t1) :t2 = e) e’ translated differently
 if true then e1 else e2 translated differently

Others:
 if? x then (if? x then e1 else e2) else e3

These people received some marks
A Much More General Solution
Do lazy injections into the sum type

Keep track of whether or not you have
done the injection using the type of the
result expression
(G |- e : t) ==> (e’ : t’)
 if t’ = (unit + unit) or (trans(t1) -> trans(t2))
then you haven’t injected the expression e’ into
a sum yet
 you can leave off unnecessary injections
around any expression, not just values
A Much More General Solution
New rules for introduction forms:
---------------------------------------------------------(G |- true : Bool?) ==> (inr (..., ()): unit + unit)
Extra rules for elimination forms:
(G |- e1 : Bool? ==> (e1’, t)
t notnull
(G |- e2 : ts ==> (e2’, t2’)
(G |- e3 : ts ==> (e3’, t3’)
e2’,e3’,t2’,t3’ unifies to e2’’,e3’’,t’’
---------------------------------------------------------(G |- if e1 then e2 else e3 : ts) ==>
if e1 then e2’’ else e3’’ : t’’
New Judgments
Natural Types:
-----------------------(unit + unit) notnull
---------------------(t1 -> t2) notnull
“Unification”
t2 = t3
------------------------------------e2,e3,t2,t3 unifies to e2,e3,t2
t2 = unit + t3
--------------------------------------------e2,e3,t2,t3 unifies to e2,inr(t2,e3),t2
t3 = unit + t2
--------------------------------------------e2,e3,t2,t3 unifies to inr(t3,e2),e3,t3
Objects
Most people did well on the definition of
the static and dynamic semantics for
objects

if you want to know some detail, come see
me during my office hours
Less well on the imperative features
Terminology

What is a closed expression?
Terminology

What is a closed expression?
 An expression containing no free variables.
 ((fun f (x:bool):bool = x x) true) is closed
 ((fun f (x:bool):bool = y x) true) is not closed
 Mathematically: if FV is a function that
computes the set of free variables of an
expression then

e is closed if and only if FV(e) = { }
Terminology

What is a well-formed expression?
Terminology

What is a well-formed expression?
 An expression that type checks under some
type context G.
 ((fun f (x:bool):bool = x x) true) is not well
formed
 ((fun f (x:bool):bool = y x) true) is well-formed
in the context G = [y:bool -> bool]
Terminology
What is (e : t) an abbreviation for?
Terminology
What is (e : t) an abbreviation for?

the typing judgment:
 . |- e : t
empty context
If (e : t) then what else do we know?
Terminology
What is (e : t) an abbreviation for?

the typing judgment:
 . |- e : t
empty context
If (e : t) then what else do we know?



we know that e contains no free variables
in other words, e is closed
(we might know other things if e also
happens to be a value)
Terminology

What is a value?
Terminology

What is a value?
 it is an expression that does not need to be
further evaluated (and it is not stuck)

How do we normally define values?
Terminology

How do we normally define values?
 We declare a new metavariable v and give its
form using BNF:
v ::= x | n | <v1,v2> | fun f (x : t1) : t2 = e
 What is the difference between a metavariable
v and an expression variable x?

Alternatively, we define a value judgment:
-------------|- x value
-------------|- n value
|- v1 value
|- v2 value
---------------------------------|- <v1,v2> value
Terminology
Does it matter whether we use BNF or a
series of judgments to define the syntax
of values and expressions?
Terminology
Does it matter whether we use BNF or a
series of judgments to define the syntax
of values and expressions?

No! BNF is just an abbreviation for the
inductive definition that we would give
using judgments instead
Why don’t we define typing rules using
BNF if it is so darn convenient?
Terminology
Does it matter whether we use BNF or a
series of judgments to define the syntax
of values and expressions?

No! BNF is just an abbreviation for the
inductive definition that we would give
using judgments instead
Why don’t we define typing rules using
BNF if it is so darn convenient?

Typing rules are context-sensitive. BNF is
used for context-insensitive definitions.
Terminology

What is strange about the following
sentence?
 If (v : t) and v is a closed, well-formed value
then the canonical forms lemma can tell us
something about the shape of v given the type
t.
Terminology

What is strange about the following
sentence?
 If (v : t) and v is a closed, well-formed value
then the canonical forms lemma can tell us
something about the shape of v given the type
t.
 The red part is totally redundant!



If you are using the metavariable v, then you should
have already defined it so that it refers to values.
(v : t) should also have been defined before. It
should trivially imply that v is closed. It defines what
it means for v to be well-formed!
If you write a sentence like this on the final, you
might find yourself losing points....
Back to objects
In the future, when I say “write an
expression that does ...” you should
always write a well-formed, closed
expression unless I specify otherwise.
{getloop =
fn (x). ({loop = fn(y).y.loop} : {loop : t})
} : {getloop : {loop : t} }
isn’t really an expression! It contains the
metavariable t.
Back to objects
{getloop =
fn (x). ({loop = fn(y).y.loop} : {loop : { }})
} : {getloop : {loop : { }} }
is what you want to do.
Imperative objects

Syntax
 t ::= {l = t,...}
 e ::= x | {l = b,...} | e.l | e.l <- b | ...
 b ::= fn(x).e
Operational semantics
Without imperative features (field
update) we can use the ordinary Mmachine definitions
e -> e’
Operational semantics
The obvious M-machine definition for
object update doesn’t work:
e = {lk = b’,l’’ = b’’...}
----------------------------------------(e.lk <- b) -> {lk = b,l’’ = b’’...}
Operational semantics
Here’s why:
this update
only has local
effect
let x = {n = fn(_).3} in
let _ = (x.n <- fn(_).2) in
x.n
let _ = ({n = fn(_).3}.n <- fn(_).2) in
{n = fn(_).3}.n
let _ = {n = fn(_).2} in
{n = fn(_).3}.n
{n = fn(_).3}.n
3
Operational semantics
We need to augment our operational
semantics with a global store.
A store S is a finite partial map from
locations (r) to values.



(what is a finite partial map?)
v ::= {l=b,...} | r
run-time expressions include locations r
Our semantics now has form:

(S,e) -> (S’,e’)
Operational semantics
Rules:
-----------------------------------------------(S, {l = b,...}) -> (S[r -> {l = b,...}], r)
S(r) = {l = fn(x).e,...}
----------------------------(S, r.l) -> (S, e[S(r)/x])
S(r) = {l = b’’, l’ = b’,...}
------------------------------------------------------(S, r.l <- b) -> (S[r -> {l = b, l’ = b’,...}], r)
Operational semantics
Our example:
empty
store
(., let x = {n = fn(_).3} in
let _ = (x.n <- fn(_).2) in
x.n)
([r -> {n = fn(_).3}],
let _ = (r.n <- fn(_).2) in
r.n)
([r -> {n = fn(_).2}],
r.n)
([r -> {n = fn(_).2}], 2)
r is substituted
for x everywhere
but the contents
of r are kept
in one place
Summary
Things to remember:


how to define type-directed and typepreserving translations
be able to use and define common terms
 values, closed expressions, operational
semantics, canonical form, inversion principle,
type system, soundness, completeness,
subtyping, the subsumption principle, etc.


proofs are for finding mistakes
imperative features are tricky
Download