CS 342 Lecture -*- Outline -*- * More advanced Scheme examples ** using functions to represent data *** finite data structures an object-oriented approach ---------------- (set point-maker (lambda (x y) (lambda (msg args) (if (= msg 'abscissa) x (if (= msg 'ordinate) y (if (= msg 'new-x) (point-maker (car args) y) (if (= msg 'new-y) (point-maker x (car args))))))) )) (set mp (point-maker 3 4)) (mp 'abscissa '()) (set send (lambda (object message args) (object message args))) (set send0 (lambda (object message) (send object message '()))) (send0 mp 'abscissa) (send mp 'new-x '(7)) ---------------- using continuations ---------------- (set point2 (lambda (x y) (lambda (f) (f x y)))) (set mp2 (point2 3 4)) (set abscissa (lambda (p) (p (lambda (x y) x)))) (set ordinate (lambda (p) (p (lambda (x y) y)))) (set new-x (lambda (p x2) (p (lambda (x y) (point2 x2 y))))) ---------------- *** infinite data structures infinite sequences ---------------- (set null-sequence ; TYPE: sequence = nat -> int (lambda (n) 0)) (set update-sequence ; TYPE: sequence, nat, int -> sequence (lambda (seq m x) (lambda (n) (if (= n m) x (seq n))))) (set nth-sequence ; TYPE: sequence, nat -> int (lambda (seq n) (seq n))) (set evens (lambda (n) (if (= (mod n 2) 0) n 0))) ---------------- ** currying, partial parameterization write max, min functions how to make a common version of these? write (extreme-value > x y) returns (max x y) (extreme-value < x y) returns (min x y) but we'd like a builder of tools, to be able to build the original functions max and min (that way we know it really generalized them) write ((extreme-value-c <) x y) use exterme-value-c to define max and min. currying allow one argument to be fixed, while others vary like projection cf. ordering examples on page 102 e.g., (round-n-places 5 r) rounds to 5 places (set round-5-places ((curry round-n-places) 5)) e.g., write curried version of nth, use it to define first, second... ** more on approaches to polymorphism. ------------ ; CURRIED FIRST APPROACH (set nullset '()) ; TYPE: all a. set of a (set addelt ;TYPE: all a. (a,a -> bool) -> a, set of a ; -> set of a (lambda (eqfun) (lambda (x s) (if ((member? eqfun) x s) s (cons x s))))) (set member? ;TYPE: all a. (a,a -> bool) ; -> (a, set of a -> bool) (lambda (eqfun) (lambda (x s) (find ((curry eqfun) x) s)))) (set union ; TYPE: all a. (a,a -> bool) ; -> (set of a, set of a) -> set of a (lambda (eqfun) (lambda (s1 s2) ((combine id (lambda (x s) (addelt x s eqfun)) s1) s2)))) ------------ easier to use (e.g., (set al-member? (member? =alist))) ------------ ; EASIER TO USE THIRD APPROACH (set mk-set-ops ; TYPE: all a. (a,a -> bool) ; -> (symbol -> function) (lambda (eqfun) (lambda (what) (if (= what 'nullset) '() (if (= what 'member?) (lambda (x s) (find ((curry eqfun) x) s)) (if (= what 'addelt) (lambda (x s) (if (find ((curry eqfun) x) s) s (cons x s))) (if (= what 'union) (lambda (s1 s2) ((combine id (lambda (x s) (addelt x s eqfun)) s1) s2))))))))) (set al-ops (mk-set-ops =alist)) (set al-nullset (al-ops 'nullset)) (set al-member? (al-ops 'member?)) (set al-addelt (al-ops 'addelt)) (set al-union (al-ops 'union)) ------------ don't have to remember or depend on order of consed stuff in mk-set-ops ------------ ; OBJECT-ORIENTED (eqfun part of objects) (set mkEqObj ; TYPE: all a. a, (a,a -> bool) ; -> EqObj of a (lambda (self eqfun) (lambda (msg) (if (= msg 'eq) (lambda (x) ; TYPE: a -> bool (eqfun self x)) (if (= msg 'value) self (error-not-understood)))) )) (set send0 (obj msg) (obj msg)) (set send1 (obj msg arg) ((obj msg) arg)) (set send2 (obj msg arg1 arg2) ((obj msg) arg1 arg2)) (set mkSet (lambda () ((lambda (initSet) (initSet '())) (lambda (self) ; TYPE: all a. list of EqObj of a ; -> Set of a (lambda (msg) (if (= msg 'addelt) (lambda (x) ; TYPE: EqObj of a -> Set of a (if (send1 self 'member? (send0 x 'value)) self (mkSet (cons x self)))) (if (= msg 'member?) (lambda (x) ; TYPE: a -> bool (find (lambda (y) (send1 e 'eq x)) self)) (if (= msg 'union) (lambda (s2) ; TYPE: Set of a -> Set of a ((combine id (lambda (x s) (send1 s addelt x)) self) s2)) (error-not-understood))))) )))) ---------------- ** continuations lambda stops evaluation, builds a closure e.g., (lambda () (+ 3 4)) is not 7 (set oh-no (lambda () (oh-no))) is not an infinite loop what's difference between lambda and quote (')? can use lambda as the ultimate "goto", saving up what to do in a closure: called a continuation e.g., pick (choosing an element from a set): what to do if the set argument is empty? work gcd example on page 108 can use lambda to build general programming control structures ** own variables variables local to a function, but whose values persist between invocations e.g., page 109 ** abstracting flat recursion program the following: sum product member-c (curried version of member) as follows: (set apply-to-all (lambda (proc) (lambda (ls) (if (null? ls) '() (cons (proc (car ls)) ((apply-to-all proc) (cdr ls))))))) abstract these to: (set flat-recur (lambda (__________________) (lambda (ls) (if (null? ls) _______ _____________________)))) (this will be like combine..., p. 102) Encapsulates a particular programming paradigm. if do this for every kind of data, can program without loops. ** term rewriting (section 4.4) they should read this note use of functions to represent substitutions...