680 likes | 688 Views
Learn how to evaluate lambda expressions in environments, bind variables in let and let* statements, and evaluate side-effecting data structures in PS4 programming.
E N D
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)) *: {mult} args: (x y) body: (* x y) env :
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) *: {mult} args: (x y) body: (* x y) env : Now apply the closure to 1 and 2...
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) *: {mult} args: (x y) body: (* x y) env : x: 1 y: 2 ...and we get 2.
(let ((x 1) (y 2)) => ((lambda (x y) (* x y)) 1 2) (* x y)) *: {mult} args: (x y) body: (* x y) env : 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)) *: {mult} args: (x y) body: (* x y) env : 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) args: x body: env: *: {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) args: x body: env: *: {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) args: x body: env: *: {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
(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... • 2. 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} f: *void* 1. create a new frame mapping f to *void* 2. link it in to the environment
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} f: *void* 3. evaluate the expression in the new environment to get a value v.
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: *void* 3. evaluate the expression in the new environment to get a value v.
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: 4. set! the binding in the frame so that f maps to v
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: 5. now evaluate the body of the letrec in the new environment.
(letrec ((f (lambda (x) (if (= 1 x) 1 (* x (f (- 1 x))))))) (f 3)) *: {mult} +: {add} =: {equal} -: {sub} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: 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} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: 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} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: 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} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: x: 3 x: 2 x: 1
(if (= 1 x) 1 (* x (f (- 1 x)))) => (* 2 (f 1)) => (* 2 1) => 2 *: {mult} +: {add} =: {equal} -: {sub} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: x: 3 x: 2
(if (= 1 x) 1 (* x (f (- 1 x)))) => (* 3 (f 2)) => (* 3 2) => 6 *: {mult} +: {add} =: {equal} -: {sub} args: x body: (if (= 1 x) 1 (* x (f (- 1 x)))) env : f: 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)) args: x body: (g x) env : f: *void* g: *void*
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) args: x body: (g x) env : f: *void* g: *void*
(letrec ((f (lambda (x) (g x))) (g (lambda (y) (f y)))) (f 0)) args: x body: (g x) env : f: *void* g: *void* args: y body: (f y) env :