CS 251 Fall 2019 CS 251 Fall 2019 Principles of Programming - - PowerPoint PPT Presentation

cs 251 fall 2019 cs 251 fall 2019 principles of
SMART_READER_LITE
LIVE PREVIEW

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


slide-1
SLIDE 1

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

slide-2
SLIDE 2

Topics

  • Lexical vs dynamic scope
  • Closures implement lexical scope.
  • Design considerations: why lexical scope?
  • Relevant design dimensions

Lexical Scope and Function Closures 2

slide-3
SLIDE 3

A question of scope (warmup)

Lexical Scope and Function Closures 3

What is the argument value passed to this function application?

(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y))))

slide-4
SLIDE 4

A question of scope

Lexical Scope and Function Closures 4

What is the value of x when this function body is evaluated for this function application?

(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y))))

slide-5
SLIDE 5

A question of free variables

Lexical Scope and Function Closures 5

To what bindings do free variables of a function refer when the function is applied?

(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) x is a free variable

  • f the lambda expression.

A variable, x, is fr free in an expression, e, if x is referenced in e

  • utside the scope of any binding of x within e.
slide-6
SLIDE 6

Answer 1: lexical (static) scope

Lexical Scope and Function Closures 6

Free variables of a function refer to bindings in the environment where the function is de defined, regardless of where it is applied.

(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) x is a free variable

  • f the lambda expression.

A variable, x, is fr free in an expression, e, if x is referenced in e

  • utside the scope of any binding of x within e.
slide-7
SLIDE 7

Answer 2: dynamic scope

Lexical Scope and Function Closures 7

Free variables of a function refer to bindings in the environment where the function is ap applied, regardless of where it is defined.

(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) x is a free variable

  • f the lambda expression.

A variable, x, is fr free in an expression, e, if x is referenced in e

  • utside the scope of any binding of x within e.
slide-8
SLIDE 8

Answer 2: dynamic scope

Lexical Scope and Function Closures 8

Free variables of a function refer to bindings in the environment where the function is ap applied, regardless of where it is defined.

(define x 1) (define f (lambda (y) (+ x y))) (define z (let ([x 2] [y 3]) (f (+ x y)))) x is a free variable

  • f the lambda expression.

A variable, x, is fr free in an expression, e, if x is referenced in e

  • utside the scope of any binding of x within e.
slide-9
SLIDE 9

Closures implement lexical scope.

Closures allow functions to use any binding in the environment where the function is defined, regardless of where it is applied.

Lexical Scope and Function Closures 9

slide-10
SLIDE 10

Anonymous function definition expressions

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

Week 1

slide-11
SLIDE 11

Function application (call)

Sy Syntax: (e0 e1 ... en) Ev Evalu luati tion:

  • 1. Under the current dynamic environment, E,

evaluate e0 through en to values v0, …, vn.

  • 2. If v0 is a function closure of n arguments,

⟨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

Week 1

slide-12
SLIDE 12

Function application (call)

Sy Synta ntax: (e0 e1 … en) Ev Evaluation:

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]

Week 1

slide-13
SLIDE 13

(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) ))

Example: returning a function

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:

slide-14
SLIDE 14

(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) ))

Example: returning a function

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

slide-15
SLIDE 15

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) ))

Example: returning a function

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)) ) )

slide-16
SLIDE 16

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) ))

Example: returning a function

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)) ) )

slide-17
SLIDE 17

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) ))

Example: returning a function

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)) ) )

slide-18
SLIDE 18

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) ))

Example: returning a function

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

slide-19
SLIDE 19

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) ))

Example: returning a function

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

slide-20
SLIDE 20

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) ))

Example: returning a function

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

slide-21
SLIDE 21

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) ))

Example: returning a function

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)) ) )

slide-22
SLIDE 22

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) ))

Example: returning a function

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)) ) )

slide-23
SLIDE 23

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) ))

Example: returning a function

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)) ) )

slide-24
SLIDE 24

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) ))

Example: returning a function

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)) ) )

slide-25
SLIDE 25

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)) ) )

Example: returning a function

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

slide-26
SLIDE 26

Debrief

  • 1. Closures implement lexical scope.
  • 2. Function bodies can use bindings from the

environment where they were defined, not where they were applied.

  • 3. The environment is not a stack.

– 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

slide-27
SLIDE 27

PL design quiz

Java methods and C functions do not need closures because they _________________.

  • a. cannot refer to names defined outside the

method/function

  • b. are not first class values
  • c. do not use lexical scope
  • d. are not anonymous (i.e., they are named)

Which, if any, are correct? Why?

Lexical Scope and Function Closures 27

slide-28
SLIDE 28

Why lexical scope?

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

slide-29
SLIDE 29

Why lexical scope?

1.

  • 1. Function meaning does not depend on name choices.

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

  • ther variable named

q is used in f.

slide-30
SLIDE 30

Why lexical scope?

2.

  • 2. Fu

Functions can be understood fully where defined. There are no "hidden parameters."

Example:

– 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

slide-31
SLIDE 31

Why lexical scope?

3a

  • 3a. Closures automatically “remember” the data they need.

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))

slide-32
SLIDE 32

Why lexical scope?

3b

  • 3b. Closures are a useful way to avoid re

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)))

slide-33
SLIDE 33

Dynamic scope?

  • Lexical scope is definitely the right default for variables.

– Nearly all modern languages

  • Early LISP used dynamic scope.

– Even though inspiration (lambda calculus) has lexical scope. – Later "fixed" by Scheme (Racket's parent) and other languages. – Emacs Lisp still uses dynamic scope.

  • Dynamic scope is very occasionally convenient:

– Racket has a special way to do it. – Perl has something similar. – Most languages are purely lexically scoped. – Ex Except ption

  • n raise

se/handle, throw/catch is s like dynamic sc scope

  • pe.

Lexical Scope and Function Closures 33

slide-34
SLIDE 34

Remember when things evaluate!

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

slide-35
SLIDE 35

Relevant PL design dimensions

in the Racket language:

– scope: lexical (static)

  • vs. dynamic

– parameter passing: pass-by-value (call-by-value)

  • vs. by-reference, by-name, by-need

– evaluation order: eager (strict)

  • vs. lazy

in our semantics of the Racket language:

– environments and closures

  • vs. substitution

– big-step operational semantics

  • vs. small-step

More on all of these dimensions (and alternatives) later!

Lexical Scope and Function Closures 35