Lecture 09
Lexical Scope and
Function Closures
Programming Languages
UW CSE 341 - Spring 2023
Lexical Scope
Lexical Scope
Lexical Scope 😇
Dynamic Scope 👿
Example
(* 1 *) let x = 1
(* 2 *) let f y = x + y
(* 3 *) let x = 2
(* 4 *) let y = 3
(* 5 *) let z = f (x + y)
Closures
Example Redux
(* 1 *) let x = 1
(* 2 *) let f y = x + y
(* 3 *) let x = 2
(* 4 *) let y = 3
(* 5 *) let z = f (x + y)
Lexical Scope via Closures
The Rule Stays the Same
Returning a
Function
“Trust the rule”: Line 4 binds g to a closure:
(* 1 *) let x = 1
(* 2 *) let f y =
(* 2 a *) let x = y + 1 in
(* 2 b *) fun q -> x + y + q
(* 3 *) let x = 3
(* 4 *) let g = f 4
(* 5 *) let y = 5
(* 6 *) let z = g 6
Passing a
Function
(* 1 *) let f g =
(* 1 a *) let x = 3 in
(* 1 b *) g 2
(* 2 *) let x = 4
(* 3 *) let h y = x + y
(* 4 *) let z = f h
Why Lexical Scope?
Why Lexical Scope?
1. Functions meaning does not depend on variable names, only “shape”
Example: can remove unused variables
Example: can change f to use w instead of x
let f y =
let x = y + 1 in
fun q -> x + y + q
let f g =
let x = 3 in
g 2
Why Lexical Scope?
2. Functions can be type checked and reasoned about where they are defined
let x = 1
let f y = (* f : int -> (int -> int) *)
let x = y + 1 in
fun q -> x + y + q
let x = "hi"
let g = f 4
let z = g 6
Why Lexical Scope?
3. Closures can easily store the data they need
let rec filter f =
fun xs ->
match xs with
| [] -> []
| x :: xs' ->
if f x then
x :: filter f xs'
else
filter f xs'
let greater_than x =
fun y -> x < y
let is_positive =
greater_than 0
let only_positives =
filter is_positive
let all_greater (xs, n) =
filter (greater_than n) xs
Does Dynamic Scope Even Exist?
When Things Evaluate
Recomputation
These both work and are equivalent
First version computes String.length s repeatedly (once per x in xs)
Second version computes String.length s once before filtering
let all_shorter (xs,s) =
filter (fun x -> String.length x < String.length s) xs
let all_shorter' xs s =
let n = String.length s in
filter (fun x -> String.length x < n) xs
Fold
let rec fold_left (f, acc, xs) =
match xs with
| [] -> acc
| x :: xs' -> fold_left (f, f (acc, x), xs')
Iterators