Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
CSE 341 22sp
CSE 341 22sp public
Commits
30b634fb
Commit
30b634fb
authored
May 04, 2022
by
James R. Wilcox
Browse files
code from today
parent
def09d66
Changes
2
Hide whitespace changes
Inline
Sidebyside
lecture/L17/lec17.ml
0 → 100644
View file @
30b634fb
(* Lexical Scope and Function Closures *)
(* lexical scope examples to learn the rules *)
(* 1 *)
let
x
=
1
(* 2 *)
let
f
y
=
x
+
y
(* 3 *)
let
x
=
2
(* 4 *)
let
y
=
3
(* 5 *)
let
z
=
f
(
x
+
y
)
(* 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
(* 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
(* let y = 5 *)
(* lexical scope examples to motivate the rules *)
(* f1 and f2 are always the same, no matter where used *)
let
f1
y
=
let
x
=
y
+
1
in
fun
z
>
x
+
y
+
z
let
f2
y
=
let
q
=
y
+
1
in
fun
z
>
q
+
y
+
z
let
h1
=
f1
7
let
h2
=
f2
7
let
x
=
17
(* irrelevant *)
let
a1
=
h1
4
let
a2
=
h2
4
(* f3 and f4 are always the same, no matter what argument is passed in *)
let
f3
g
=
let
x
=
3
in
(* irrelevant *)
g
2
let
f4
g
=
g
2
let
x
=
17
let
a3
=
f3
(
fun
y
>
x
+
y
)
let
a4
=
f4
(
fun
y
>
x
+
y
)
let
a5
=
f3
(
fun
y
>
17
+
y
)
let
a6
=
f4
(
fun
y
>
17
+
y
)
(* under dynamic scope, the call to g below would:
 try to add a string x to an int
 have an unbound variable y
even though g type checked! *)
let
x
=
"hi"
let
g
=
f1
7
let
z
=
g
4
(* lexical scope examples to leverage the rules *)
(* lexical scope very useful with higherorder functions *)
(* our first example of "currying"; will study and use
more soon
*)
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
(* let's start using that e1 e2 e3 is (e1 e2) e3 *)
let
all_shorter
(
xs
,
s
)
=
filter
(
fun
x
>
String
.
length
x
<
String
.
length
s
)
xs
let
all_shorter'
(
xs
,
s
)
=
(* why is this potentially faster? *)
let
n
=
String
.
length
s
in
filter
(
fun
x
>
String
.
length
x
<
n
)
xs
let
rec
fold_left
(
f
,
acc
,
xs
)
=
match
xs
with

[]
>
acc

x
::
xs'
>
fold_left
(
f
,
(
f
(
acc
,
x
))
,
xs'
)
(* examples that do not capture private data *)
let
sum
xs
=
fold_left
((
fun
(
acc
,
x
)
>
acc
+
x
)
,
0
,
xs
)
let
only_positives
xs
=
fold_left
((
fun
(
acc
,
x
)
>
acc
&&
x
>=
0
)
,
true
,
xs
)
(* examples that *do* capture private data *)
let
count_in_range
(
lo
,
hi
,
xs
)
=
fold_left
((
fun
(
acc
,
x
)
>
acc
+
(
if
lo
<=
x
&&
x
<
hi
then
1
else
0
))
,
0
,
xs
)
let
are_all_shorter
(
xs
,
s
)
=
let
n
=
String
.
length
s
in
fold_left
((
fun
(
acc
,
x
)
>
acc
&&
String
.
length
x
<
n
)
,
true
,
xs
)
let
forall
(
f
,
xs
)
=
fold_left
((
fun
(
acc
,
x
)
>
acc
&&
f
x
)
,
true
,
xs
)
let
only_positives'
xs
=
forall
((
fun
x
>
x
>
0
)
,
xs
)
let
are_all_shorter'
(
xs
,
s
)
=
let
n
=
String
.
length
s
in
forall
((
fun
x
>
String
.
length
x
<
n
)
,
xs
)
lecture/L17/lec17live.ml
0 → 100644
View file @
30b634fb
(* lexical scope *)
let
x
=
1
(* [x > 1] *)
let
f
y
=
x
+
y
(* f is a function which adds 1 to its argument *)
let
f2
y
=
1
+
y
(* f and f2 are guaranteed to be equivalent
but only because of lexical scope!! *)
(* many lines later ... *)
let
x
=
2
let
y
=
3
(* [y>3, x>2, f > ..., x>1] *)
let
z
=
f
(
x
+
y
)
(* under dynamic scope evaluate the body (x + y) in this extended environment *)
(* [y>5, y>3, x>2, f > ..., x>1] *)
(* under dynamic scope, f 5 returns 7 *)
(* rule for lexical scope:
 look up f in the current environment, get a function binding
 get the defining environment
 evaluate arguments in the current environment
 evaluate the body in the *defining* environment, extended by arg names > arg values
*)
(* opposite of lexical scope: dynamic scope *)
(* rule for dynamic scope:
 look up f in the current environment, get a function binding
 evaluate arguments in the current environment
 evaluate the body in the *current* environment, extended by arg names > arg values
*)
(* scope in the presence of firstclass functions *)
(* Q: what does (fun x > x + 1) evaluate to? *)
let
x
=
1
let
f
=
(
fun
y
>
y
+
x
)
let
f_old_syntax
y
=
y
+
x
let
x
=
2
let
n
=
f
5
(* should be 6 *)
(* a new kind of value!
a CLOSURE (yaaaay!)
 the code of a function
 a dynamic environment
basically identical to FunctionEntry, with two differences
 now it's called something different
 it's a *value*, not and entry
now we can define the semantics of anonymous function
 anonymous functions are not values!!!
 they evaluate to a closure containing their code and the current environment
*)
let
x
=
1
let
f
=
(
fun
y
>
y
+
x
)
(* evaluating this line produces a closure
 code: (fun y > y + x)
 env: the current dynamic environment
 pretend no code above this in file,
 then the current environment is [x > 1]
*)
let
f_old_syntax
y
=
y
+
x
let
x
=
2
let
n
=
f
5
(* should be 6 *)
(*
evaluate "f 5"
 evaluate f in the current environment to a value v
 if v is not a closure, signal an error
 otherwise, let (c, e) be the code and environment from the closure
 evaluate the arguments to values in the current environment
 evaluate c in the environment e extended by arg names > arg vals mappings
*)
(* officially, we need to update the syntax of function calls
 old syntax: f e where f is a string which should be the name of a function, and e is any expression
 new syntax: e1 e2 where e1 and e2 are any expressions
(fun x > x + 1) 5
(let f = (fun x > x + 1) in f) 5
*)
(*
Now that we have "new functions" aka closures, we don't need global function bindings any more
anywhere we used to write
let f x = x + 1
(define (f x) (+ x 1))
we can treat this as an abbreviation for
let f = fun x > x + 1
(define f (lambda (x) (+ x 1)))
*)
(* example with returning a function as a result *)
let
x
=
1
(* [x > 1] *)
let
f
y
=
let
x
=
y
+
1
in
fun
q
>
x
+
y
+
q
(* [f > (code, [x>1]), x > 1] *)
(* the type of f is int > (int > int) or removing unnecessary parens, int > int > int *)
(* f is a function that takes an arg y and:
 returns a function that takes an arg q and:
 it returns 2 * y + 1 + q
*)
let
x
=
3
(* [x > 3, f > (code, [x>1]), x > 1] *)
let
g
=
f
4
(* g has type int > int *)
(* evaluate the code of f in [y > 4, x > 1]
in the body of the let, have
[x > 5, y > 4, x > 1]
create a closure ((fun q > x + y + q), [x > 5, y > 4, x > 1])
*)
(* [g > that thing ^ , x > 3, f > (code, [x>1]), x > 1] *)
(* g is a function that takes an arg q and adds 2 * 4 + 1 to q, in other words, g adds 9 to its arg *)
let
y
=
5
(* [y > 5, g > that thing ^ , x > 3, f > (code, [x>1]), x > 1] *)
let
z
=
g
6
(*
evaluate x + y + q in [q > 6, x > 5, y > 4, x > 1]
*)
(* z should be 15 *)
(* example of taking a function as an argument *)
let
f
g
=
let
x
=
3
in
g
2
let
x
=
4
let
h
y
=
x
+
y
(* adds four to arg *)
let
z
=
f
h
(* z is 6 *)
(* (under dynamic scope, would compute 5 instead) *)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment