CS 251 Fall 2019 Principles of Programming Languages
Ben Wood
λ
CS 251 Fall 2019
Principles of Programming Languages
Ben Wood
λ
https://cs.wellesley.edu/~cs251/f19/
Lexical Scope and Function Closures
Lexical Scope and Function Closures 1
CS 251 Fall 2019 CS 251 Fall 2019 Principles of Programming - - PowerPoint PPT Presentation
CS 251 Fall 2019 CS 251 Fall 2019 Principles of Programming Languages Principles of Programming Languages Ben Wood Ben Wood Lexical Scope and Function Closures https://cs.wellesley.edu/~cs251/f19/ 1 Lexical Scope and Function
CS 251 Fall 2019 Principles of Programming Languages
Ben Wood
CS 251 Fall 2019
Principles of Programming Languages
Ben Wood
https://cs.wellesley.edu/~cs251/f19/
Lexical Scope and Function Closures 1
Lexical Scope and Function Closures 2
Lexical Scope and Function Closures 3
(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y))))
Lexical Scope and Function Closures 4
(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y))))
Lexical Scope and Function Closures 5
(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) x is a free variable
A variable, x, is fr free in an expression, e, if x is referenced in e
Lexical Scope and Function Closures 6
(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) x is a free variable
A variable, x, is fr free in an expression, e, if x is referenced in e
Lexical Scope and Function Closures 7
(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) x is a free variable
A variable, x, is fr free in an expression, e, if x is referenced in e
Lexical Scope and Function Closures 8
(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) x is a free variable
A variable, x, is fr free in an expression, e, if x is referenced in e
Lexical Scope and Function Closures 9
Sy Syntax: (lambda (x1 … xn) e)
– pa parameters: x1 through xn are identifiers – bo body: e is any expression
Ev Evaluation:
1. The result is a fu function c closure, ⟨E, (lambda (x1 … xn) e)⟩, holding the current environment, E, and the function.
Note:
– An anonymous function definition is an expression. – A function closure is a new kind of value. Closures are not expressions. – This is a de definition, not a call. . The body, e, is no not evaluated now. – lambda from the λ-ca calcu culus.
10
E ⊢ (lambda (x1 … xn) e) ↓ ⟨E, (lambda (x1 … xn) e)⟩ [closure]
Lexical Scope and Function Closures
Sy Syntax: (e0 e1 ... en) Ev Evalu luati tion:
evaluate e0 through en to values v0, …, vn.
⟨E', (lambda (x1 … xn) e)⟩ then The result is the result of evaluating the closure body, e, under the closure environment, E', extended with argument bindings: x1 ⟼ v1, …, xn ⟼ vn. Otherwise, there is a type error.
Functions 11
Functions 12
E ⊢ e0 ↓ ⟨E', (lambda (x1 … xn) e)⟩ E ⊢ e1 ↓ v1 … E ⊢ en ↓ vn x1 ⟼ v1, …, xn ⟼ vn, E' ⊢ e ↓ v E ⊢ (e0 e1 … en) ↓ v [apply]
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 13
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
de def de def
Current evaluation step: Current environment:
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 14
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1
de def de def
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 15
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1
f
de def de def
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 16
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1
f
de def le let le let de def
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 17
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x
de def le let de def le let
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 18
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x y
4
de def le let le let de def app app app app
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
app app
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 19
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x y
4
x
5
de def le let le let de def app app a p p a p p
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
a p p a p p
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 20
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x y
4
x
5
env
(lambda (z) (+ x y z))
de def le let le let de def app app app app
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
app app
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 21
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x y
4
x
5
env
(lambda (z) (+ x y z))
g
de def le let le let de def
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 22
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x y
4
x
5
env
(lambda (z) (+ x y z))
y
5
g
de def le let le let de def
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 23
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x y
4
x
5
env
(lambda (z) (+ x y z))
y
5
g z
6
de def le let app app a p p a p p le let de def a p p a p p
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
Lexical Scope and Function Closures 24
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x y
4
x
5
env
(lambda (z) (+ x y z))
y
5
g z
6
de def le let app app app app app app
15
le let de def
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
env
(define x 1) (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) (define z (let ([x 3] [g (f 4)] [y 5]) (g 6) ))
(lambda (y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) ) )
Lexical Scope and Function Closures 25
env pointer
shows env structure, by pointing to “rest of environment”
binding
maps variable name to value
x
1 3
f x y
4
x
5
env
(lambda (z) (+ x y z))
y
5
g z
6
z
15
de def d e d e f f
– Multiple environments (branches) may be live simultaneously. – CS 240's basic stack model will not suffice. – General case: heap-allocate the environment. GC will clean up for us!
Lexical Scope and Function Closures 26
method/function
Lexical Scope and Function Closures 27
Le Lexical al sc scope: use environment where function is de defined. d. Dy Dynami mic scope: use environment where function is appl applied. History has shown that lexical scope is almost always better. Here are some precise, technical reasons (not opinion).
Lexical Scope and Function Closures 28
1.
Example: change body of f to replace x with q.
– Lexical scope: it cannot matter – Dynamic scope: depends how result is used (define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z))))
Example: remove unused variables.
– Dynamic scope: but maybe some g uses it (weird). (define (f g) (let ([x 3]) (g 2)))
Lexical Scope and Function Closures 29
(! (!) ) It is is important in both cases that no
q is used in f.
2.
Functions can be understood fully where defined. There are no "hidden parameters."
– Dynamic scope tries to add #f, unbound variable y, and 4.
(define (f y) (let ([x (+ y 1)]) (lambda (z) (+ x y z)) (define x #f) (define g (f 7)) (define a (g 4))
Lexical Scope and Function Closures 30
3a
More examples, idioms later.
Lexical Scope and Function Closures 31
(define (greater-than-x x) (lambda (y) (> y x))) (define (no-negs xs) (filter (greater-than-x -1) xs)) (define (all-greater xs n) (filter (lambda (x) (> x n)) xs))
3b
recomputatio ion. These functions filter lists of lists by length. How many times is the length function called?
Lexical Scope and Function Closures 32
(define (all-shorter-than-1 lists mine) (filter (lambda (xs) (< (length xs) (length mine))) lists)) (define (all-shorter-than-2 lists mine) (let ([len (length mine)]) (filter (lambda (xs) (< (length xs) len)) lists)))
– Nearly all modern languages
– Even though inspiration (lambda calculus) has lexical scope. – Later "fixed" by Scheme (Racket's parent) and other languages. – Emacs Lisp still uses dynamic scope.
– Racket has a special way to do it. – Perl has something similar. – Most languages are purely lexically scoped. – Ex Except ption
se/handle, throw/catch is s like dynamic sc scope
Lexical Scope and Function Closures 33
A function body is no not evalua uated ed unt until the function is called. A function body is ev evaluated ev every time the function is called. A binding evaluates its expression wh when the binding is evaluated, not every time the variable is used.
As with lexical/dynamic scope, there are other options here that Racket does no not use. We will consider some later.
Lexical Scope and Function Closures 34
in the Racket language:
– scope: lexical (static)
– parameter passing: pass-by-value (call-by-value)
– evaluation order: eager (strict)
in our semantics of the Racket language:
– environments and closures
– big-step operational semantics
More on all of these dimensions (and alternatives) later!
Lexical Scope and Function Closures 35