Substitution & Evaluation Order cos 441 David Walker Reading • Pierce Chapter 5: – 5.1: intro, op. sem., evaluation order – 5.2: encodings of booleans, pairs, numbers, recursion – 5.3: substitution Substitution • In order to be precise about the operational semantics of the lambda calculus, we need to define substitution properly • For the call-by-value operational semantics, we need to define: – e1 [v/x] where v contains no free variables • For other operational semantics, we need: – e1 [e2/x] Free Variables FV : Given an expression, compute its free variables FV : lambda expression variable set FV(x) = {x} FV(e1 e2) = FV(e1) U FV(e2) FV(\x.e) = FV(e) – {x} FV as an inductive definition FV(x) = {x} Previous slide: FV(e1 e2) = FV(e1) U FV(e2) FV(\x.e) = FV(e) – {x} FV(x) = {x} Equivalent definition: FV(e1) = S1 FV(e2) = S2 FV(e1 e2) = S1 U S2 FV(e) = S FV(\x.e) = S – {x} All Variables Vars(x) = {x} Vars(e1 e2) = Vars(e1) U Vars(e2) Vars(\x.e) = Vars(e) U {x} substitution examples (\x.\y.z z)[\w.w/z] = \x.\y.(\w.w) (\w.w) examples (\x.\y.z z)[\w.w/z] = \x.\y.(\w.w) (\w.w) (\x.\z.z z)[\w.w/z] = \x.\z.z z examples (\x.\y.z z)[\w.w/z] = \x.\y.(\w.w) (\w.w) (\x.\z.z z)[\w.w/z] = \x.\z.z z (\x.x z)[x/z] = \x.x x ? examples (\x.\y.z z)[\w.w/z] = \x.\y.(\w.w) (\w.w) (\x.\z.z z)[\w.w/z] = \x.\z.z z (\x.x z)[x/z] = \x.x x (\x.x z)[x/z] = (\y.y z)[x/z] = \y.y x alpha-equivalent expressions = the same except for consistent renaming of variables “special” substitution (ignoring capture issues) definition of e1 [[e/x]] assuming FV(e) Vars(e1) = { }: x [[e/x]] y [[e/x]] e1 e2 [[e/x]] (\x.e1) [[e/x]] (\y.e1) [[e/x]] =e =y = (e1 [[e/x]]) (e2 [[e/x]]) = \x.e1 = \y.(e1 [[e/x]]) (if y ≠ x) (if y ≠ x) The Principle of “Bound Variable Names Don’t Matter” when you write “let val x = 3 in x + global end” you assume you can change the declaration of x to a declaration of y (or other name) provided you systematically change the uses of x. eg: “let val y = 3 in y + global end” provided that the name you pick doesn’t conflict with the free variables of the expression. eg: “let val global = 3 in global + global end” bad Alpha-Equivalence in order to avoid variable clashes, it is very convenient to alpha-convert expressions so that bound variables don’t get in the way. eg: to alpha-convert \x.e we: 1. 2. pick z such that z not in Vars(\x.e) return \z.(e[[z/x]]) we just defined this form of substitution e[[z/x]] so it is a total function when z is not in Vars(\x.e) terminology: Expressions e1 and e2 are called alphaequivalent when they are the same after alphaconverting some of their bound variables capture-avoiding substitution defined inductively on the structure of exp’s: x [e/x] y [e/x] e1 e2 [e/x] (\x.e1) [e/x] (\y.e1) [e/x] (\y.e1) [e/x] =e = y (if y ≠ x) = (e1 [e/x]) (e2 [e/x]) = \x.e1 = \y.(e1 [e/x]) (if y ≠ x and y FV(e)) = \z.((e1[[z/y]]) [e/x]) (if y ≠ x and y FV(e)) for some z such that z FV(e) U Vars(e1) Implicit Alpha-Conversion it’s irritating to explicitly alpha-convert all the time in our definitions. ie: to explicitly write down that before doing something like substitution (or type checking) that we are going to pick some new variable z that doesn’t interfere with any other variables in the current context and alpha-convert the given term. Consequently, we are going to take a short-cut: implicit alpha-conversion. When dealing with a bound variable as in \x.e, we’ll just assume that x is any variable we like other than one of the free variables in e. capture-avoiding substitution (the short-cut definition) x [e/x] y [e/x] e1 e2 [e/x] (\x.e1) [e/x] (\y.e1) [e/x] =e = y (if y ≠ x) = (e1 [e/x]) (e2 [e/x]) = \x.e1 = \y.(e1 [e/x]) (if y ≠ x and y FV(e)) (note, we left out the case for \y.e1 [e/x] when y ≠ x and y FV(e). We’ll implicitly alpha-convert \y.e1 to \z.e1[[z/y]] for some z that doesn’t appear in e1 whenever we need to satisfy the free variable side conditions) operational semantics again (\x.e) v --> e [v/x] e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ • Is this the only possible operational semantics? alternatives (\x.e) v --> e [v/x] (\x.e1) e2 --> e1 [e2/x] e1 --> e1’ e1 e2 --> e1’ e2 e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ call-by-value call-by-name alternatives (\x.e) v --> e [v/x] e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ call-by-value (\x.e1) e2 --> e1 [e2/x] e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ e1 e2 --> e1 e2’ e --> e’ \x.e --> \x.e’ full beta-reduction alternatives (\x.e) v --> e [v/x] (\x.e) v --> e [v/x] e1 --> e1’ e1 e2 --> e1’ e2 e1 --> e1’ e1 v --> e1’ v e2 --> e2’ v e2 --> v e2’ call-by-value e2 --> e2’ e1 e2 --> e1 e2’ right-to-left call-by-value Multi-step Op. Sem • Given a single step op sem. relation: e1 --> e2 • We extend it to a multi-step relation by taking its “reflexive, transitive closure:” e1 -->* e1 (reflexivity) e1 --> e2 e2 -->* e3 e1 -->* e3 (transitivity) Proving Theorems About O.S. Call-by-value o.s.: (\x.e) v --> e [v/x] e1 --> e1’ e1 e2 --> e1’ e2 e2 --> e2’ v e2 --> v e2’ To prove property P of e1 --> e2, there are 3 cases: case: (\x.e) v --> e [v/x] Must prove: P((\x.e) v --> e [v/x]) ** Often requires a related property of substitution e [v/x] case: e1 --> e1’ e1 e2 --> e1’ e2 IH = P(e1 --> e1’) Must prove: P(e1 e2 --> e1’ e2) case: e2 --> e2’ v e2 --> v e2’ IH = P(e2 --> e2’) Must prove: P(v e2 --> v e2’) Proving Theorems About O.S. Call-by-value o.s.: e1 -->* e1 (reflexivity) e1 --> e2 e2 -->* e3 e1 -->* e3 (transitivity) To prove property P of e1 -->* e2, given you’ve already proven property P’ of e1 --> e2, there are 2 cases: case: e1 -->* e1 Must prove: P(e1 -->* e1) directly case: e1 --> e2 e2 -->* e3 e1 -->* e3 IH = P(e2 -->* e3) Also available: P’(e1 --> e2) Must prove: P(e1 -->* e3) Example Definition: An expression e is closed if FV(e) = { }. Theorem: If e1 is closed and e1 -->* e2 then e2 is closed. Proof: by induction on derivation of e1 -->* e2. summary • the operational semantics – primary rule: beta-reduction – depends upon careful definition of substitution – many evaluation strategies • definitions/terminology to remember: – free variable – bound variable – closed expression – capture-avoiding substitution – alpha-equivalence; alpha-conversion – call-by-value, call-by-name, full beta reduction