PS4 #6: if you got points off because you didn’t do an
intersect with accessible and the start states, submit a regrade.
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))
(let ((x2 e2))
...
(let ((xn en))
e)))
(((...(lambda (x1)
((lambda (x2)
=>
...
((lambda (xn) e)...))
e1) e2) ... en)
(let* ((x 3)
(y (* x x)))
(* x y))
(let ((x 3))
=>
(let ((y (* x x))
(* x y)))
=>
((lambda (x) ((lambda (y) (* x y)) (* x x))) 3)
*: {mult}
(let* ((x 3)
(y (* x x)))
(* x y))
(let ((x 3))
=>
(let ((y (* x x))
(* x y)))
=>
((lambda (x) ((lambda (y) (* x y)) (* x x))) 3)
args: x
body:
env:
*: {mult}
(let* ((x 3)
(y (* x x)))
(* x y))
(let ((x 3))
=>
(let ((y (* x x))
(* x y)))
=>
((lambda (x) ((lambda (y) (* x y)) (* x x))) 3)
args: x
body:
env:
*: {mult}
x:3
(let* ((x 3)
(y (* x x)))
(* x y))
(let ((x 3))
=>
(let ((y (* x x))
(* x y)))
=>
((lambda (x) ((lambda (y) (* x y)) (* x x))) 3)
args: x
body:
env:
*: {mult}
x:3
(let* ((x 3)
(y (* x x)))
(* x y))
(let ((x 3))
=>
(let ((y (* x x))
(* x y)))
=>
((lambda (x) ((lambda (y) (* x y)) (* x x))) 3)
*: {mult}
x:3
(let* ((x 3)
(y (* x x)))
(* x y))
(let ((x 3))
=>
(let ((y (* x x))
(* x y)))
=>
((lambda (x) ((lambda (y) (* x y)) (* x x))) 3)
*: {mult}
args: y
body: (* x y)
env:
x:3
(let* ((x 3)
(y (* x x)))
(* x y))
(let ((x 3))
=>
(let ((y (* x x))
(* x y)))
=>
((lambda (x) ((lambda (y) (* x y)) (* x x))) 3)
*: {mult}
args: y
body: (* x y)
env:
x:3
And then we apply the closure to 9...
(let* ((x 3)
(y (* x x)))
(* x y))
(let ((x 3))
=>
(let ((y (* x x))
(* x y)))
=>
((lambda (x) ((lambda (y) (* x y)) (* x x))) 3)
*: {mult}
args: y
body: (* x y)
env:
x:3
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.
3.
4.
5.
link the
evaluate
set! the
evaluate
frame into E yielding a new environment E’
each ei in the new environment E’ to a value vi
bindings in the frame so that xi maps to vi
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}
f:
x: 3
args: x
body: (if (= 1 x) 1
(* x (f (- 1 x))))
env :
(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:
x: 3
args: x
body: (if (= 1 x) 1
(* x (f (- 1 x))))
env :
(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}
f:
x: 3
args: x
body: (if (= 1 x) 1
(* x (f (- 1 x))))
env :
(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 :
(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:
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:
x: 0
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))
args: x
body: (g x)
env :
f:
g:
x: 0
y: 0
args: y
body: (f y)
env :
Alternative:
to evaluate
(letrec ((x1 e1)
...
(xn en))
e)
in environment E, evaluate?
(let ((x1 ‘void)
...
(xn ‘void))
(let ((v1 e1)
...
(vn en))
(set! x1 v1)
...
(set! xn vn)
e))
; define place-holders
; evaluate e1,...,en
; and save values as v1,...,vn
; set x1,...,xn to v1,...,vn
(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
(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 :
(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
v1:
v2:
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:
g: ‘void
v1:
v2:
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:
g:
v1:
v2:
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:
g:
v1:
v2:
args: x
body: (g x)
env :
args: y
body: (f y)
env :
Mutable Data
(define mylist (list 1 2 3))
(let ((new (list 4)))
(set! (tail new) (tail mylist))
(set! (tail mylist) new))
mylist
1
2
3 ()
Mutable Data
(define mylist (list 1 2 3))
(let ((new (list 4)))
(set! (tail new) (tail mylist))
(set! (tail mylist) new))
mylist
new
1
2
4
()
3 ()
Mutable Data
(define mylist (list 1 2 3))
(let ((new (list 4)))
(set! (tail new) (tail mylist))
(set! (tail mylist) new))
mylist
new
1
2
4
3 ()
Mutable Data
(define mylist (list 1 2 3))
(let ((new (list 4)))
(set! (tail new) (tail mylist))
(set! (tail mylist) new))
mylist
new
X
1
4
2
3 ()
Mutable Data
(define mylist (list 1 2 3))
(let ((new (list 4)))
(set! (tail new) (tail mylist))
(set! (tail mylist) new))
mylist
new
1
2
4
3 ()
© Copyright 2026 Paperzz