Introduction Even though the syntax of Scheme is



















![Some Wrong Answers: (lambda (x) x)[3/x] = (lambda (x) 3) (lambda (x) x)[3/x] = Some Wrong Answers: (lambda (x) x)[3/x] = (lambda (x) 3) (lambda (x) x)[3/x] =](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-20.jpg)

![Substitution Rules 1 -5 are easy No variable, no substitution: s 1. num[v/x] = Substitution Rules 1 -5 are easy No variable, no substitution: s 1. num[v/x] =](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-22.jpg)
![Examples for rules s 4 -s 5 (+ 3 2)[#t/y] = (by s 4) Examples for rules s 4 -s 5 (+ 3 2)[#t/y] = (by s 4)](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-23.jpg)
![Substitution: The Real Action s 6. y [v/x] = v if y and x Substitution: The Real Action s 6. y [v/x] = v if y and x](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-24.jpg)
![Example For Rule s 6: (+ y x)[3/y] = (by s 4) (+[3/y] y[3/y] Example For Rule s 6: (+ y x)[3/y] = (by s 4) (+[3/y] y[3/y]](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-25.jpg)
![Example for rule s 7: (lambda (x y) (+ z y))[3/z] = (s 7 Example for rule s 7: (lambda (x y) (+ z y))[3/z] = (s 7](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-26.jpg)
![Another Example for rule s 7 (lambda (x y) (+ z y))[3/y] = (s Another Example for rule s 7 (lambda (x y) (+ z y))[3/y] = (s](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-27.jpg)
![Yet another 7 example (lambda (x y) (+ z y))[3/w] = (s 7 b) Yet another 7 example (lambda (x y) (+ z y))[3/w] = (s 7 b)](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-28.jpg)
![Revisiting: (lambda (x) x)[3/x] = (lambda (x) x) (by s 7 a) Why? The Revisiting: (lambda (x) x)[3/x] = (lambda (x) x) (by s 7 a) Why? The](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-29.jpg)




















- Slides: 49

Introduction Even though the syntax of Scheme is simple, it can be very difficult to determine the semantics of an expression. Hacker’s approach: Run it and see what happens. • What if it behaves differently on different machines or with different arguments? • What if you’re in charge of writing the first compiler? CS 212 approach: Construct a formal, mathematical model.

Overview Develop the model by starting with an extremely simple language and work our way up. – arithmetic – if, booleans – lambda, variables – substitution Goal: be able to construct a formal proof that a given Scheme program evaluates to a specified value.

Scheme-0 Syntax: num op : : = + | - | * | / (expressions) e : : = num | op | (e 1 … en ) (numbers) (operators) English: Expressions are either numbers, an operator (+, -, *, or /) or a combination which is a sequence of nested expressions surrounded by parentheses. Note: we use blue to denote meta-variables

Scheme-0 Values (values) v : : = num | op English: Values are either numbers or an operator. Values are a subset of expressions. Well-formed expressions evaluate to a value. We write e => v when expression e evaluates to value v.

Rules for Evaluation There are just two for Scheme-0: One for values, and one for certain kinds of combinations. If no rule applies, then the program is illformed. (Dr. Scheme reports an error. )

Evaluation Rule 1: Values v => v English: a value evaluates to itself. Examples: 3 => 3 (by rule 1) + => + (by rule 1)

Evaluation Rule 2: Arithmetic To prove (e 1 e 2 e 3) => v show: (a) e 1 => op (e 1 evaluates to an operator) (b) e 2 => v 1 (e 2 evaluates to a value) (c) e 3 => v 2 (e 3 evaluates to a value) (d) v 1 op v 2 = v (applying the operator to the values yields the value v. )

Evaluation Rule 2 example: (+ 3 4) => 7 (by rule 2) (a) + => + (by rule 1, since + is a value) (b) 3 => 3 (by rule 1, since 3 is a value) (c) 4 => 4 (by rule 1, since 4 is a value) (d) 3+4 = 7 (by math)

Scheme-1: op : : = + | - | * | / | < | > | = bool : : = #t | #f e : : = num | op | (e 1 … en ) | (if e 1 e 2 e 3) | bool v : : = num | op | bool • We added booleans (as values) and if expressions. • #t is true, #f is false.

Eval. Rules 1 and 2 are the same: 1. v => v Examples: #t => #t, < => < 2. (e 1 e 2 e 3) => v if: (a) e 1 => op (b) e 2 => v 1 (c) e 3 => v 2 (d) v 1 op v 2 = v Examples: (< 3 4) => #t

Evaluation Rule 3 a: (if #f) To prove (if e 1 e 2 e 3) => v show: (a) e 1 => #f (b) e 3 => v Example: (if (< 3 1) -1 0) => 0 (by rule 3 a) (< 3 1) => #f (by rule 2) (a) < => < (by rule 1) (b) 3 => 3 (by rule 1) (c) 1 => 1 (by rule 1) (d) 3 < 1 = #f (by math) (b) 0 => 0 (by rule 1)

Evaluation Rule 3 b (if #t) To prove (if e 1 e 2 e 3) => v show: (a) e 1 => v 1 and v 1 is not #f (b) e 2 => v Example: (if (> 3 1) -1 0) => -1 (by rule 3 a) (> 3 1) => #t (by rule 2) (a) > => > (by rule 1) (b) 3 => 3 (by rule 1) (c) 1 => 1 (by rule 1) (d) 3 > 1 = #t (by math) (b) -1 => -1 (by rule 1)

Notes on If Unlike other combinations, if is lazy. For non-if combinations (rule 2): – evaluate arguments to values eagerly – apply operator to values For if combinations (rule 3): – evaluate first argument (only) to value – if it’s #f, then evaluate third argument (3 a) – otherwise, evaluate second argument (3 b)

Scheme-2 e : : = num | op | (e 1 … en ) | (if e 1 e 2 e 3) | bool | fn | x v : : = num | op | bool | fn fn : : = (lambda (x 1 … xn) e) • We add lambda expressions (functions) and variables. – We use x to represent an arbitrary variable • Note that functions are values (i. e. , lambdas evaluate to themselves. ) • Previous rules (1, 2, 3 a, 3 b) still apply • It’s an error to run into an unbound variable.

Eval. Rule 4: (most important) To prove (e 1 e 2 e 3 … en) => v show: (a) e 1 => (lambda (x 2 x 3… xn) e) (b) e 2 => v 2, e 3 => v 3, …, en => vn (c) e[v 2/x 2, v 3/x 3 , … , vn/xn] = e’ (i. e. , substitute v 2, …, vn for x 2, …, xn in e) (d) e’ => v • We’ll formally define substitution later.

Example: ((lambda (x) (if x 3 (* 4 2))) #f) => 8 (by 4) (a) (lambda (x) (if x 3 (* 4 2))) => (lambda (x) (if x 3 (* 4 2))) (by 1) (b) #f => #f (by 1) (c) (if x 3 (* 4 2))[#f/x] = (if #f 3 (* 4 2)) (by subst. ) (d) (if #f 3 (* 4 2)) => 8 (by 3 a) (a) #f => #f (by 1) (b) (* 4 2) => 8 (by 2, subgoals obvious)

Another Example: (((lambda (x) (lambda (y) y)) 3) 5) => 5 (by rule 4) (a) ((lambda (x) (lambda (y) y)) 3) => (lambda (y) y) (by rule 4 & proof below) (b) 5 => 5 (c) y[5/y] = 5 (by rule 1) (by substitution) (d) 5 => 5 (by rule 1) So now all we have to show is part (a). . .

Example Continued ((lambda (x) (lambda (y) y)) 3) => (lambda (y) y) (by rule 4) (a) (lambda (x) (lambda (y) y)) => (lambda (x) (lambda (y) y)) (by rule 1) (b) 3 => 3 (by rule 1) (c) (lambda (y) y)[3/x] = (lambda (y) y) (by subst. ) (d) (lambda (y) y) => (lambda (y) y) (by rule 1)

Hmmmm. . . Consider changing y to x systematically: Old: ((lambda (x) (lambda (y) y)) 3) New: ((lambda (x) x)) 3) Body of outer function Following rule 4: (a) (lambda (x) x)) => (lambda (x) x)) (b) 3 => 3 (c ) (lambda (x) x)[3/x] = ? ? ?
![Some Wrong Answers lambda x x3x lambda x 3 lambda x x3x Some Wrong Answers: (lambda (x) x)[3/x] = (lambda (x) 3) (lambda (x) x)[3/x] =](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-20.jpg)
Some Wrong Answers: (lambda (x) x)[3/x] = (lambda (x) 3) (lambda (x) x)[3/x] = (lambda (3) 3) Why are these wrong? – The first x is a binding occurrence (the name of a parameter) – The second x is a free occurrence that refers to a use of the nearest enclosing bound variable. – This is called lexical scope for variables.

Formalizing Substitution e : : = num | op | (e 1 … en ) | (if e 1 e 2 e 3) | bool | x | (lambda (x 1…xn) e) We write e[v 1/x 1, …, vn/xn] as an abbreviation for performing the substitutions one at a time. So all we really need to define formally is e[v/x]. We do so by cases on e (7 cases):
![Substitution Rules 1 5 are easy No variable no substitution s 1 numvx Substitution Rules 1 -5 are easy No variable, no substitution: s 1. num[v/x] =](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-22.jpg)
Substitution Rules 1 -5 are easy No variable, no substitution: s 1. num[v/x] = num ex: 3[#t/y]=3 s 2. op[v/x] = op ex: +[#t/y]=+ s 3. bool[v/x] = bool ex: #f[#t/x]=#f Usually, just push the substitution in: s 4. (e 1 … en )[v/x] = (e 1 [v/x] … en [v/x]) s 5. (if e 1 e 2 e 3)[v/x] = (if e 1 [v/x] e 2 [v/x] e 3 [v/x] )
![Examples for rules s 4 s 5 3 2ty by s 4 Examples for rules s 4 -s 5 (+ 3 2)[#t/y] = (by s 4)](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-23.jpg)
Examples for rules s 4 -s 5 (+ 3 2)[#t/y] = (by s 4) (+[#t/y] 3[#t/y] 2[#t/y]) = (+ 3 2) because +[#t/y] = + 3[#t/y]= 3 2[#t/y]= 2 (by s 2) (by s 1) (if #f 3 2)[#t/y] = (by s 5) (if #f[#t/y] 3[#t/y] 2[#t/y]) = (if #f 3 2)
![Substitution The Real Action s 6 y vx v if y and x Substitution: The Real Action s 6. y [v/x] = v if y and x](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-24.jpg)
Substitution: The Real Action s 6. y [v/x] = v if y and x are the same = y otherwise s 7. (lambda (x 1…xn) e) [v/x] = a. (lambda (x 1…xn) e) if x is one of x 1…xn. b. (lambda (x 1…xn) e[v/x]) if x is not one of x 1…xn. Substitution Rule 7 is very important!!!
![Example For Rule s 6 y x3y by s 4 3y y3y Example For Rule s 6: (+ y x)[3/y] = (by s 4) (+[3/y] y[3/y]](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-25.jpg)
Example For Rule s 6: (+ y x)[3/y] = (by s 4) (+[3/y] y[3/y] x[3/y]) = (+ 3 x) because +[3/y] = + y[3/y]= 3 x[3/y]= x (by s 2) (by s 6 -- notice y = y) (by s 6 -- notice x y)
![Example for rule s 7 lambda x y z y3z s 7 Example for rule s 7: (lambda (x y) (+ z y))[3/z] = (s 7](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-26.jpg)
Example for rule s 7: (lambda (x y) (+ z y))[3/z] = (s 7 b) (lambda (x y) (+ z y)[3/z] ) = (s 5) (lambda (x y) (+[3/z] z[3/z] y[3/z] )) = (s 2) (lambda (x y) (+ z[3/z] y[3/z] )) = (s 6 a) (lambda (x y) (+ 3 y[3/z] )) = (s 6 b) (lambda (x y) (+ 3 y)) = (s 2) In the first line, rule s 7 b applies because the variable we’re replacing (z) does not occur as a parameter to the function.
![Another Example for rule s 7 lambda x y z y3y s Another Example for rule s 7 (lambda (x y) (+ z y))[3/y] = (s](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-27.jpg)
Another Example for rule s 7 (lambda (x y) (+ z y))[3/y] = (s 7 a) (lambda (x y) (+ z y)) Why? Because the variable we’re substituting for (y) is one of the parameters, so we do not push the substitution in to the body of the function.
![Yet another 7 example lambda x y z y3w s 7 b Yet another 7 example (lambda (x y) (+ z y))[3/w] = (s 7 b)](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-28.jpg)
Yet another 7 example (lambda (x y) (+ z y))[3/w] = (s 7 b) (lambda (x y) (+ z y)[3/w] ) = (s 5) (lambda (x y) (+[3/w] z[3/w] y[3/w] )) = (s 2) (lambda (x y) (+ z[3/w] y[3/w] )) = (s 6 b) (lambda (x y) (+ z y)) = (s 2) This time, the variable we’re replacing (w) is not one of the parameters, but it doesn’t occur in the body of the function so it disappears!
![Revisiting lambda x x3x lambda x x by s 7 a Why The Revisiting: (lambda (x) x)[3/x] = (lambda (x) x) (by s 7 a) Why? The](https://slidetodoc.com/presentation_image/19ae2a3ac10cdcdbdca565443706d96c/image-29.jpg)
Revisiting: (lambda (x) x)[3/x] = (lambda (x) x) (by s 7 a) Why? The x that we’re substituting 3 for was shadowed by another definition. Most (modern) languages have similar scoping rules -- inner definitions of variables hide outer definitions.

Summary Formalized evaluation of Scheme-2 – Gave syntax of expressions • numbers, operators, combinations, booleans, if, and lambda. – Gave syntax-directed rules for evaluating expressions to values. – Substitution comes into play for user-defined functions. – Lexical scope determines rules for when we substitute what. Still need to cover define. . .

Scheme-3 Expressions and values are as before. . . (programs) (defines) p : : = d 1 … dn e d : : = (define x e) The top-level declarations allow us to define global variables (usually functions). But they require a slightly different model. . .

Top-Level Environments: An Environment (Env) is a way to keep track of top-level bindings. It simply maps (some) variables to values. Example: {x: =3, y: =#t} English: if you see x while evaluating, replace it with 3 and if you see y, replace it with #t.

Intuition: Suppose our program is: (define x (+ 3 4)) (define inc (lambda (x) (+ x 1))) (inc x) We evaluate as follows: – start with an empty environment Env 0 = {} – evaluate (+ 3 4) in Env 0, yielding 7 and bind x to 7 resulting in Env 1 = {x: =7} – bind inc to the lambda-value resulting in Env 2 = {x: =7, inc: =(lambda (x) (+ x 1))} – evaluate (inc x) in Env 2 replacing inc with (lambda (x) (+ x 1)) and x with 7 to get 8.

Three New Things: 1. Env |- e => v Same as before except if we run into a free variable while evaluating e, we look it up in Env. 2. Env 1 |- d => Env 2 Evaluating a definition yields a new environment (with that definition) 3. P => v A program yields a value. Intuitively, start with an empty environment, evaluate definitions to get a new environment, and then evaluate the expression of the program.

Revisiting Evaluation Rules 1 and 2 1. Env |- v => v (no real change) 2. Env |- ( e 1 e 2 e 3 ) => v if: (a) Env |- e 1 => op (b) Env |- e 2 => v 1 (c) Env |- e 3 => v 2 (d) Env |- v 1 op v 2 = v

Evaluation Rule 3: 3 a. Env |- (if e 1 e 2 e 3) => v if: (a) Env |- e 1 => #f (b) Env |- e 3 => v 3 b. Env |- (if e 1 e 2 e 3) => v if: (a) Env |- e 1 => v’ and v’ is not #f (b) Env |- e 3 => v

Evaluation Rule 4: Env |- (e 1 e 2 e 3 … en) => v if: (a) Env |- e 1 => (lambda (x 2 x 3… xn) e) (b) Env |- e 2 => v 2 , …, Env |- en => vn (c) e[v 2/x 2 , … , vn/xn] = e’ (d) Env |- e’ => v

Eval. Rule 5: (new rule -- variables) Env |- x => v if x is mapped to v by Env. That is, Env has a binding x: =v in it.

Eval. Rule 6: (new rule -- define) To prove Env |- (define x e) => Env{x: =v} show Env |- e => v That is, first evaluate e in the current environment Env to yield a value v. Then bind v to the variable x to yield a new environment (for subsequent evaluation. )

Eval. Rule 7: (new rule -- program) To prove d 1 … dn e => v show: (a) {} |- d 1 => Env 1 … Envn-1 |- dn => Envn (b) Envn |- e => v That is, start with an empty environment, evaluate the definitions (in order), take the final environment and use it to evaluate e.

Putting it all together: Let’s prove that evaluating the program P below yields 6. (define z 1) (define w (* 3 z)) (define f (lambda (n) (if (< n 2) 1 (+ n (f (- n 1)))))) (f w)

First Define We start off in an empty environment ({}) and show: {} |- (define z 1)=> {z: = 1} (by rule 6) because {} |- 1 => 1 (by rule 1)

Second Define {z: =1} |- (define w (* z 3)) => {z: =1, w: =3} (6) because {z: =1} |- (* z 3) => 3 (2): (a) {z: =1} |- * => * (1) (b) {z: =1} |- z => 1 (5 -- note lookup) (c) {z: =1} |- 3 => 3 (1) (d) 1*3 = 3 (by math) So our 2 nd environment is {z: =1, w: =3}.

Third Define: This one is easy like the first one, because the expression is already a value (a lambda): {z: =1, w: =3} |- (define f (lambda (n) …)) => Env where Env is {z: =1, w: =3, f: =(lambda (n) …)} by the fact that {z: =1, w: =3} |- (lambda (n) …) => (lambda (n) …) (rule 1). Finally, we must show that Env |- (f w) => 6.

Final Expression: Env |- (f w) => 6 (4) (a) Env |- f => (lambda (n) (if (< n 2) 2 (+ n (f(- n 1))))) (5 since f maps to (lambda (n) …) in Env) (b) Env |- w => 3 (5 since w maps to 3 in Env) (c) (if (< n 2) 1 (+ n (f (- n 1))))[3/n] = (if (< 3 2) 1 (+ 3 (f (- 3 1))))(subst)

Continuing. . . (d) Env |(if (< 3 2) 1 (+ 3 (f (- 3 1)))) =>6(3 a) (a) Env |- (< 3 2) => #f (2 & obvious) (b) Env |- (+ 3 (f (- 3 1))) => 6 (2) +, 3 obvious, need to show Env |- (f (- 3 1)) => 3

And on. . . Env |- (f (- 3 1)) => 3 (by 4) (a) Env |- f => (lambda (n) (if …)) (by 5) (b) Env |- (- 3 1) => 2 (by 2 & obvious) (c) (if …)[2/n] = (if (< 2 2) 1 (+ 2 (f (- 2 1)))) (by subst) (d) Env |- (if (< 2 2) 1 (+ 2 (f (- 2 1)))) => 3 (by 3 a)

And on. . . (a) Env |- (< 2 2) => #f (2 & obvious) (b) Env |- (+ 2 (f (- 2 1))) => 3 (2) +, 2 obvious, need to show Env |- (f (- 2 1)) => 1 (4) (a) Env |- f => (lambda (n) (if …)) (5) (b) Env |- (- 2 1) => 1 (2 & obvious) (c) (if …)[1/n] = (by subst. ) (if (< 1 2) 1 (+ 1 (f (- 1 1)))) (d) Env |- (if (< 1 2) 1 …) => 1 (3 b)

And on. . . Env |- (if (< 1 2) 1 …) => 1 (3 b) (a) Env |- (< 1 2) => #t (2) (b) Env |- 1 => 1 (1) Therefore, adding up the last umpteen slides, the program evaluates to 6. Note: though many steps were skipped, they were obvious. When in doubt, do all of the steps.