CS 251 Fall 2019 CS 251 Spring 2020 Topics Principles of - - PowerPoint PPT Presentation

cs 251 fall 2019 cs 251 spring 2020 topics principles of
SMART_READER_LITE
LIVE PREVIEW

CS 251 Fall 2019 CS 251 Spring 2020 Topics Principles of - - PowerPoint PPT Presentation

CS 251 Fall 2019 CS 251 Spring 2020 Topics Principles of Programming Languages Principles of Programming Languages Ben Wood Ben Wood Lexical vs dynamic scope Lexical Scope Closures implement lexical scope. Design


slide-1
SLIDE 1

CS 251 Fall 2019 Principles of Programming Languages

Ben Wood

λ

CS 251 Spring 2020

Principles of Programming Languages

Ben Wood

λ

https://cs.wellesley.edu/~cs251/s20/

Lexical Scope and Function Closures

+closures.rkt

Lexical Scope and Function Closures 1

Topics

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

Lexical Scope and Function Closures 2

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

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-2
SLIDE 2

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.

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.

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.

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-3
SLIDE 3

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

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.

Lexical Scope and Function Closures 10

E ⊢ (lambda (x1 … xn) e) ↓ ⟨E, (lambda (x1 … xn) e)⟩ [closure]

Week 1 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 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-4
SLIDE 4

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

(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

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

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-5
SLIDE 5

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

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

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

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-6
SLIDE 6

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

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

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

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

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

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

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

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-8
SLIDE 8

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.

Why lexical scope?

2.

  • 2. Fu

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

Example:

– Under 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

Why lexical scope?

3a

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

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

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 during all-shorter…?

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-9
SLIDE 9

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

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 function call's ar arguments ar are eval aluat ated before the he cal called fu function's s body. 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

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 definitions of the Racket language (subset):

– 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