520 likes | 618 Views
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.
E N D
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 type-preserving?
Type-preserving Translations • When is a translation is type-preserving? • 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: • Example: --------------------------------------------------------------------------- (G |- true : Bool?) ==> inr (Trans(Bool?), inl (unit + unit, ())) (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 | inr (z) => z x)) this is a function 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 • 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 (G |- e : t) ==> (e’ : t’)
A Much More General Solution • New rules for introduction forms: • Extra rules for elimination forms: ---------------------------------------------------------- (G |- true : Bool?) ==> (inr (..., ()): unit + unit) (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: • “Unification” ------------------------ (unit + unit) notnull ---------------------- (t1 -> t2) notnull 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 • If (e : t) then what else do we know? empty context
Terminology • What is (e : t) an abbreviation for? • the typing judgment: • . |- e : t • 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) empty context
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: |- v1 value |- v2 value ---------------------------------- |- <v1,v2> value -------------- |- x value -------------- |- n 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 M-machine 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 this update only has local effect • Here’s why: 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)