PS4 #6: if you got points off because you didn’t do an intersect with accessible and the start states, submit a re- grade. Today: let, let*, letrec in the env. model side-effecting lists (set-car!, set-cdr!) Tomorrow: more on side-effecting data structures (e.g., chains)
To evaluate a lambda in environment E, build a closure. To evaluate a (non-special form) combination: (f a1... an) in E: evaluate f in E and get a closure c evaluate each argument ai in E to get a value vi apply the closure c to the values v1... vn To apply a closure c to values v1... vn: build a new frame, binding closure formal parameters to actual parameters v1... vn link the frame into the environment of the closure to yield a new environment evaluate the body of the closure in the new environment
To evaluate: (let ((x1 e1) (x2 e2)... (xn en)) e) in environment E: 1. evaluate e1, e2,..., en in environment E producing values v1, v2,..., vn. 2. build a new frame that binds x1 to v1, x2 to v2,..., xn to vn. 3. link the new frame into E to yield a new environment. 4. evaluate the body of the let, e, in the new environment.
(let ((x 1) (y 2)) (* x y)) *: {mult} 1. evaluate 1 and 2 in the current env.
(let ((x 1) (y 2)) (* x y)) *: {mult} x: 1 y: 2 2. build new frame with bindings 3. link it in to the env.
(let ((x 1) (y 2)) (* x y)) *: {mult} x: 1 y: 2 4. evaluate body of let in new env.
(let ((x 3) (y (* x x))) (* x y)) *: {mult} 1. evaluate 1 in environment to get 1...
(let ((x 3) (y (* x x))) (* x y)) *: {mult}...but evaluating (* x x) fails! (no binding for x in the environment!)
Alternative: (let ((x1 e1) (x2 e2)... (xn en)) e) in environment E, evaluate: ((lambda (x1 x2... xn) e) e1 e2... en)
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) *: {mult}
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) *: {mult}
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) args: (x y) body: (* x y) env : *: {mult}
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) args: (x y) body: (* x y) env : *: {mult} Now apply the closure to 1 and 2...
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) args: (x y) body: (* x y) env : *: {mult} x: 1 y: 2...and we get 2.
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) args: (x y) body: (* x y) env : *: {mult} x: 1 y: 2 afterwards, we continue evaluating in the top-level environment...
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) args: (x y) body: (* x y) env : *: {mult} x: 1 y: 2 and the intermediate closure and frame are garbage collected
To evaluate: (let* ((x1 e1) (x2 e2)... (xn en)) e) in environment E: 1. evaluate e1 in E to v1 2. add a new frame mapping x1 to v1, yielding E2 3. evaluate e2 in E2 to v2 4. add a new frame mapping x2 to v2, yielding E3... 2n-1. evaluate en in En to vn 2n. add a new frame mapping xn to vn, yielding E’ 2n+1. evaluate the body e in E’
(let* ((x 3) (y (* x x))) (* x y)) *: {mult}
(let* ((x 3) (y (* x x))) (* x y)) *: {mult} x:3
(let* ((x 3) (y (* x x))) (* x y)) *: {mult} x:3 The (* x x) yields 9...
(let* ((x 3) (y (* x x))) (* x y)) *: {mult} x:3 y:9
(let* ((x 3) (y (* x x))) (* x y)) *: {mult} x:3 y:9 The (* x y) yields 3*9 = 27
Alternative: (let* ((x1 e1) (x2 e2)... (xn en)) e) in environment E, evaluate: (let ((x1 e1)) (((...(lambda (x1) (let ((x2 e2)) ((lambda (x2)... =>... (let ((xn en)) ((lambda (xn) e)...)) e))) e1) e2)... en)
(let* ((x 3) (let ((x 3)) (y (* x x))) => (let ((y (* x x)) => (* x y)) (* x y))) ((lambda (x) ((lambda (y) (* x y)) (* x x))) 3) *: {mult}
(let* ((x 3) (let ((x 3)) (y (* x x))) => (let ((y (* x x)) => (* x y)) (* x y))) ((lambda (x) ((lambda (y) (* x y)) (* x x))) 3) *: {mult} args: x body: env:
(let* ((x 3) (let ((x 3)) (y (* x x))) => (let ((y (* x x)) => (* x y)) (* x y))) ((lambda (x) ((lambda (y) (* x y)) (* x x))) 3) *: {mult} args: x body: env: x:3
(let* ((x 3) (let ((x 3)) (y (* x x))) => (let ((y (* x x)) => (* x y)) (* x y))) ((lambda (x) ((lambda (y) (* x y)) (* x x))) 3) *: {mult} args: x body: env: x:3
(let* ((x 3) (let ((x 3)) (y (* x x))) => (let ((y (* x x)) => (* x y)) (* x y))) ((lambda (x) ((lambda (y) (* x y)) (* x x))) 3) *: {mult} x:3
(let* ((x 3) (let ((x 3)) (y (* x x))) => (let ((y (* x x)) => (* x y)) (* x y))) ((lambda (x) ((lambda (y) (* x y)) (* x x))) 3) *: {mult} x:3 args: y body: (* x y) env:
(let* ((x 3) (let ((x 3)) (y (* x x))) => (let ((y (* x x)) => (* x y)) (* x y))) ((lambda (x) ((lambda (y) (* x y)) (* x x))) 3) *: {mult} x:3 args: y body: (* x y) env: And then we apply the closure to 9...
(let* ((x 3) (let ((x 3)) (y (* x x))) => (let ((y (* x x)) => (* x y)) (* x y))) ((lambda (x) ((lambda (y) (* x y)) (* x x))) 3) *: {mult} x:3 args: y body: (* x y) env: y:9...and as before get 27 as the result.
To evaluate: (letrec ((x1 e1) (x2 e2)... (xn en)) e) in environment E: 1. build a new frame mapping each xi to *void* looking up *void* should be an error link the frame into E yielding a new environment E’ 3. evaluate each ei in the new environment E’ to a value vi 4. set! the bindings in the frame so that xi maps to vi 5. evaluate the body e in E’
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} 1. create a new frame mapping f to *void*
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} 1. create a new frame mapping f to *void* 2. link it in to the environment f: *void*
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} 3. evaluate the expression in the new environment to get a value v. f: *void*
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} 3. evaluate the expression in the new environment to get a value v. f: *void* args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env :
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} 4. set! the binding in the frame so that f maps to v f: args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env :
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} 5. now evaluate the body of the letrec in the new environment. f: args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env :
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} f: args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : x: 3
(if (= 1 x) 1 (* x (f (- 1 x)))) => (if (= 1 3) 1 (* x (f (- 1 x)))) => (if #f 1 (* x (f (- 1 x)))) => (* x (f (- 1 x))) => (* 3 (f (- 1 x))) => (* 3 (f 2)) *: {mult} +: {add} =: {equal} -: {sub} f: args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : x: 3
(if (= 1 x) 1 (* x (f (- 1 x)))) => (if (= 1 2) 1 (* x (f (- 1 x)))) => (if #f 1 (* x (f (- 1 x)))) => (* x (f (- 1 x))) => (* 2 (f (- 1 x))) => (* 2 (f 1)) *: {mult} +: {add} =: {equal} -: {sub} f: args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : x: 3 x: 2
(if (= 1 x) 1 (* x (f (- 1 x)))) => (if (= 1 1) 1 (* x (f (- 1 x)))) => (if #t 1 (* x (f (- 1 x)))) => 1 *: {mult} +: {add} =: {equal} -: {sub} f: args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : x: 3 x: 2 x: 1
(if (= 1 x) 1 (* x (f (- 1 x)))) => (* 2 (f 1)) => (* 2 1) => 2 *: {mult} +: {add} =: {equal} -: {sub} f: args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : x: 3 x: 2
(if (= 1 x) 1 (* x (f (- 1 x)))) => (* 3 (f 2)) => (* 3 2) => 6 *: {mult} +: {add} =: {equal} -: {sub} f: args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : x: 3
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0))
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: *void* g: *void*
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: *void* g: *void*
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: *void* g: *void* args: x body: (g x) env :
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: *void* g: *void* args: x body: (g x) env :
args: y body: (f y) env : (letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: *void* g: *void* args: x body: (g x) env :
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: g: args: x body: (g x) env : args: y body: (f y) env :
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: g: args: x body: (g x) env : args: y body: (f y) env :
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: g: args: x body: (g x) env : args: y body: (f y) env : x: 0
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) f: g: args: x body: (g x) env : args: y body: (f y) env : x: 0 y: 0
Alternative: to evaluate (letrec ((x1 e1)... (xn en)) e) in environment E, evaluate? (let ((x1 ‘void) ; define place-holders... (xn ‘void)) (let ((v1 e1) ; evaluate e1,...,en... ; and save values as v1,...,vn (vn en)) (set! x1 v1) ; set x1,...,xn to v1,...,vn... (set! xn vn) e))
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) => (let ((f ‘void) (g ‘void)) (let ((v1 (lambda (x) (g x))) (v2 (lambda (y) (f y)))) (set! f v1) (set! g v2) (f 0)))
(let ((f ‘void) (g ‘void)) (let ((v1 (lambda (x) (g x))) (v2 (lambda (y) (f y)))) (set! f v1) (set! g v2) (f 0))) f: ‘void g: ‘void
f: ‘void g: ‘void args: x body: (g x) env : (let ((f ‘void) (g ‘void)) (let ((v1 (lambda (x) (g x))) (v2 (lambda (y) (f y)))) (set! f v1) (set! g v2) (f 0)))
f: ‘void g: ‘void args: x body: (g x) env : args: y body: (f y) env : (let ((f ‘void) (g ‘void)) (let ((v1 (lambda (x) (g x))) (v2 (lambda (y) (f y)))) (set! f v1) (set! g v2) (f 0)))
f: ‘void g: ‘void args: x body: (g x) env : args: y body: (f y) env : v1: v2: (let ((f ‘void) (g ‘void)) (let ((v1 (lambda (x) (g x))) (v2 (lambda (y) (f y)))) (set! f v1) (set! g v2) (f 0)))
f: g: ‘void args: x body: (g x) env : args: y body: (f y) env : v1: v2: (let ((f ‘void) (g ‘void)) (let ((v1 (lambda (x) (g x))) (v2 (lambda (y) (f y)))) (set! f v1) (set! g v2) (f 0)))
f: g: args: x body: (g x) env : args: y body: (f y) env : v1: v2: (let ((f ‘void) (g ‘void)) (let ((v1 (lambda (x) (g x))) (v2 (lambda (y) (f y)))) (set! f v1) (set! g v2) (f 0)))
f: g: args: x body: (g x) env : args: y body: (f y) env : v1: v2: (let ((f ‘void) (g ‘void)) (let ((v1 (lambda (x) (g x))) (v2 (lambda (y) (f y)))) (set! f v1) (set! g v2) (f 0)))
Mutable Data (define mylist (list 1 2 3)) (let ((new (list 4))) (set! (tail new) (tail mylist)) (set! (tail mylist) new)) () mylist
4 () new Mutable Data (define mylist (list 1 2 3)) (let ((new (list 4))) (set! (tail new) (tail mylist)) (set! (tail mylist) new)) mylist ()
new Mutable Data (define mylist (list 1 2 3)) (let ((new (list 4))) (set! (tail new) (tail mylist)) (set! (tail mylist) new)) mylist ()
new Mutable Data (define mylist (list 1 2 3)) (let ((new (list 4))) (set! (tail new) (tail mylist)) (set! (tail mylist) new)) mylist () X
Mutable Data (define mylist (list 1 2 3)) (let ((new (list 4))) (set! (tail new) (tail mylist)) (set! (tail mylist) new)) new mylist ()