Commit 30b634fb authored by James R. Wilcox's avatar James R. Wilcox
Browse files

code from today

parent def09d66
(* 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 higher-order 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)
(* 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 first-class 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) *)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment