CS 342 Lecture -*- Outline -*- * lambda advert: major focus of Scheme, only difference from LISP general purpose tool-builder effect: understand lambda as function builder, static scope ** lambda builds functions (closures) each type of data has constructors and observers (recall CLU) symbols: ' (quote) and eq? numbers: literals and +, -, <, >, =, ... s-exprs: '(), cons and car, cdr, null? closures: lambda and application application only way to manipulate a closure, since a black box --------------------------- Mathematical notation: f(y) = 1 + y Church's lambda notation: (lambda (y) (+ 1 y)) LISP: (define add1 (y) (+ 1 y)) Scheme (our version): (set add1 (lambda (y) (+ 1 y))) ---------------------------- *** closures are data values **** part of data structures (cons add1 '()) **** new defintion of s-expressions: either number, symbol, primitive operation (+, <) or a closure, or a list of of s-expressions **** passed as arguments see page 96 ------------- -> (sort2 7 5 (lambda (x y) (> x y))) (7 5) ------------- **** returned from functions see page 97 ------------- (set compose (lambda (f g) (lambda (x) (f (g x))))) (set cadr (compose car cdr)) (cadr '(1 2 3)) == ((compose car cdr) '(1 2 3)) == (((lambda (f g) (lambda (x) (f (g x)))) car cdr) '(1 2 3)) == ((lambda (x) (car (cdr x))) '(1 2 3)) == (car (cdr '(1 2 3))) == (car '(2 3)) ---------- *** what is a closure? function def (lambda expression) + environment e.g. in (lambda (x) (+ one x)), what is meaning of "one"? taken from enviroment in which lambda is evaluated (run-time) notation: <<(lambda (x) (+ one x)), {one |-> 1}>> Note: this is a bit misleading, since actually close over cells, not values draw the picture to show the closures in above examples (see page 113 for what envs should look like) refer to the picture (see above) "one" above is called a "free" variable. "x" is a "bound" variable an object in Smalltalk can be thought of as containing several closures that share a common environment *** how are closures used in evaluation? must evaluate operator position i.e., in (e1 e2) must get value of e1 if get a primop, just do it if get a closure, extend environment with actuals, then evaluate body ** scope area of program in which a declaration (formal or set stmt) has an effect ------------ (set addx (lambda (x) (lambda (x) (+ x x)))) (set addx3 (addx 3)) -> (addx3 1) 2 ; this is NOT a mistake, it shows the scope ------------ draw envrionment diagram (boxes) for addx. *** environment extension formalizes scope rules in Pascal notation: let rho = {x |-> 1, y |-> 3} then rho{z |-> 5, x |-> 2} = {x |-> 2, y |-> 3, z |-> 5} ** examples *** mapcar (page 100) Another common pattern: see p. 100 -------------- '(1 2 3) |-> (2 3 4) '(a b) |-> ((a 3) (b 4)) test whether 7 is a member of a list '(a 7 9) |-> (() T ()) |-> T (set mapcar ; TYPE: (a -> b), list of a -> list of b (lambda (f lst) (if (null? lst) '() (cons (f (car lst)) (mapcar f (cdr lst)))))) (mapcar add1 '(1 2 3)) = (2 3 4) (mapcar (lambda (x) (list2 x 3)) '(a b)) = ((a 3) (b 4)) (mapcar (lambda (y) (= 7 y)) '(a 7 9)) = (() T ()) -------------- using combine: (set mapcar (lambda (f lst) ((combine f cons '())) lst)) *** currying mapcar Would like to have tool that makes the function without applying it. ---------- (set mapc ;TYPE:(a -> b) -> (list of a -> list of b) (lambda (f) (lambda (lst) (if (null? lst) '() (cons (f (car lst)) ((mapc f) (cdr lst))))))) ((mapc add1) '(1 2 3)) = (2 3 4) (set add1* (mapc add1)) (add1* '(2 3 1)) = (3 4 2) (set seven-checker (mapc (lambda (y) (= 7 y)))) (seven-checker '(a 7 9)) = (() T ()) ------------ *** currying in general -------------- (set false '()) (set =c ; TYPE: o -> (o -> bool) (lambda (x) (lambda (y) (= x y)))) (set seven-checker (mapc (=c 7))) (seven-checker '(a 7 9)) = (() T ()) (set member ; TYPE: a, list of a -> bool (lambda (x lst) (if (null? lst) false (if (= x lst) true (member x (cdr lst)))))) (set memberc ; TYPE: a -> (list of a -> bool) (lambda (x) (lambda (lst) (if (null? lst) false (if (= x lst) true ((memberc x) (cdr lst))))))) ; simpler still (set curry ; TYPE: (a,b -> c) -> (a -> (b -> c)) (lambda (f) (lambda (x) (lambda (y) (f x y))))) (set mapc (curry mapcar)) (set =c (curry =)) (set memberc (curry member)) -------- ; using combine: (set mapc (lambda (f) (lambda (lst) ((combine f cons '()) lst)))) ; even simpler: (set mapc (lambda (f) (combine f cons '()))) *** sets and polymorphism (page 104) **** set code (page 104) ------------ (set find ; TYPE: (a -> bool), list of a -> bool (lambda (pred lis) (if (null? lis) '() (if (pred (car lis)) 'T (find pred (cdr lis)))))) (set nullset '()) ; TYPE: set of s-exp (set addelt ;TYPE: s-exp,set of s-exp -> set of s-exp (lambda (x s) (if (member? x s) s (cons x s)))) (set member? ; TYPE: s-exp, set of s-exp -> bool (lambda (x s) (find ((curry equal) x) s))) (set union ; TYPE: set of s-exp, set of s-exp ; -> set of s-exp (lambda (s1 s2) ((combine id addelt s1) s2))) ------------ **** the problem, how to compare the elements of a set e.g., sets of pairs, sets of rational numbers sets of alists ------------ (set equal ; TYPE: s-exp, s-exp -> bool (lambda (l1 l2) (if (atom? l1) (= l1 l2) (if (atom? l2) false (if (equal (car l1) (car l2)) (equal (cdr l1) (cdr l2)) false))))) (set member? ; TYPE: s-exp, list of s-exp -> bool (lambda (x s) (if (equal x s) true (member? x (cdr s))))) (set al-member? ; TYPE: alist, list of alist -> bool (lambda (x s) (if (=alist x s) true (member? x (cdr s))))) ------------ what if also need member? for sets, for sets of pairs, ... **** approach 1: make equality test argument to each function ------------ ; FIRST APPROACH (set nullset '()) ; TYPE: all a. set of a (set addelt ;TYPE: all a. a, set of a, (a,a -> bool) ; -> set of a (lambda (x s eqfun) (if (member? x s eqfun) s (cons x s)))) (set member? ;TYPE: all a. a, set of a, (a,a -> bool) ; -> bool (lambda (x s eqfun) (find ((curry eqfun) x) s))) (set union ; TYPE: all a. set of a, set of a, ; (a,a -> bool) -> set of a (lambda (s1 s2 eqfun) ((combine id (lambda (x s) (addelt x s eqfun)) s1) s2))) ------------ **** approach 2: put the function in the set ------------ ; SECOND APPROACH (set nullset ; TYPE: all a. (a,a->bool) -> set of a (lambda (eqfun) (lst2 eqfun '()) (set set-test (lambda (s) (car s))) (set set-elems (lambda (s) (cadr s))) (set set-cons (lambda (x s) (list2 (set-test s) (cons x (set-elems))))) (set addelt ;TYPE: all a. a, set of a -> set of a (lambda (x s) (if (member? x s) s (set-cons x s)))) (set member? ;TYPE: all a. a, set of a -> bool (lambda (x s) (find ((curry (set-test s)) x) (set-elems s)))) ; ... ------------ **** approach 3: make the function part of the operations that is, build the equality test into the operations ------------ ; THIRD APPROACH (set mk-set-ops ; TYPE: all a. (a,a -> bool) ; -> list of objects + functions (lambda (eqfun) (cons '() ; empty set (cons (lambda (x s) ; member? (find ((curry eqfun) x) s)) (cons (lambda (x s) ; addelt (if (find ((curry eqfun) x) s) s (cons x s))) '() ))))) (set list-of-al-ops (mk-set-ops =alist)) (set al-nullset (car list-of-al-ops)) (set al-member? (cadr list-of-al-ops)) (set al-addelt (caddr list-of-al-ops)) ------------