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