Data abstractions Abstractions and their variations Basic data abstractions Why data abstractions are useful Procedural abstraction Process of procedural abstraction Define formal parameters, capture process in body of procedure Give procedure a name Hide implementation details from user, who just invokes name to apply procedure Input: type procedure Details of contract for converting input to output Output: type Procedural abstraction example: To find an approximation of square root of x: Make a guess G Improve the guess by averaging G and x/g Keep improving the guess until it is good enough (define try (lambda (guess x) (if (good-enuf? guess x) guess (try ( guess x) x)))) (define (lambda (guess x) (average guess (/ x guess)))) (define average (lambda (a b) (/ (+ a b) ))) (define good-enuf? (lambda (guess x) (< (abs (- (square guess) x)).))) (define (lambda (x) (try x))) The universe of procedures for average try Good-enuf? The universe of procedures for - Block Structure average try (define ( x) (define (good-enuf? guess) (< (abs (- (square guess) x)).)) (define ( guess) (average guess (/ x guess))) (define (-iter guess) (if (good-enuf? guess) guess (-iter ( guess)))) ( iter.)) Good-enuf? x: number good enuf? good enuf? x : number 6
Clean version of easy to add cbrt (define ( x) (fixed-point (average-damp (lambda (y) (/ x y))) )) Compare this to Heron s algorithm from before same process, but ideas intertwined with code Summary of part Procedural abstractions Isolate details of process from its use Designer has choice of which ideas to isolate, in order to support general patterns of computation Good planning in how to collect procedures within higher order structures can make it easier to add new computations (define (cbrt x) (fixed-point (average-damp (lambda (y) (/ x (square y)))) )) 7 8 Language Elements Primitives prim. data: numbers, strings, booleans primitive procedures Means of Combination procedure application compound data (today) Means of Abstraction naming compound procedures block structure higher order procedures (more today) conventional interfaces lists (today) data abstraction (next lecture) Compound data Need a way of gluing data elements together into a unit that can be treated as a simple data element Need ways of getting the pieces back out Need a contract between the glue and the unglue Ideally want the result of this gluing to have the property of closure: the result obtained by creating a compound data structure can itself be treated as a primitive object and thus be input to the creation of another compound object 9 Pairs (cons cells) Compound Data (cons <x-exp> <y-exp>) ==> <P> ;type: x, x Pair Where <x-exp> evaluates to a value <x-val>, and <y-exp> evaluates to a value <y-val> Treat a PAIR as a single unit: Can pass a pair as argument Can return a pair as a value Returns a pair <P> whose car-partis <x-val> and whose cdr-partis <y-val> (car <P>) ==> <x-val> ;type: Pair type of car part Returns the car-part of the pair <P> (define x y) (cons x y)) (define (point-x point) (car point)) (define (point-y point) (cdr point)) (, ) point (cdr <P>) ==> <y-val> ;type: Pair type of cdr part Returns the cdr-part of the pair <P> (define (make-seg pt pt) (cons pt pt)) (define (start-point seg) (car seg))
Pair Abstraction Constructor ; cons: A,B -> A X B ; cons: A,B -> Pair<A,B> (cons <x> <y>) ==> <P> Accessors (or Selectors) ; car: Pair<A,B> -> A (car <P>) ==> <x> ; cdr: Pair<A,B> -> B (cdr <P>) ==> <y> Pair abstraction Note how there exists a contract between the constructor and the selectors: (car (cons <a> <b> )) <a> (cdr (cons <a> <b> )) <b> Note how pairs have the property of closure we can use the result of a pair as an element of a new pair: (cons (cons ) ) Predicate ; pair? anytype -> boolean (pair? <z>) ==> #t if <z> evaluates to a pair, else #f Conventional interfaces -- lists A list is a data object that can hold an arbitrary number of ordered items. More formally, a list is a sequence of pairs with the following properties: Car-part of a pair in sequence holds an item Cdr-part of a pair in sequence holds a pointer to rest of list Empty -list signals no more pairs, or end of list Note that lists are closed under operations of cons and cdr. Conventional Interfaces - Lists (cons <el> <el>) <el> (list <el> <el>... <eln>) <el> <el> <el> <eln> Predicate ; null? anytype -> boolean (null? <z>) ==> #t if <z> evaluates to empty list 6 to be really careful For today we are going to create different constructors and selectors for a list (define first car) (define rest cdr) (define adjoin cons) Note how these abstractions inherit closure from the underlying abstractions! Common Pattern #: cons ing up a list (define (enumerate-interval from to) (if (> from to) (adjoin from (enumerate-interval (+ from) to)))) (e-i ) (if (> ) (adjoin (e i (+ ) ))) (if #f (adjoin (e-i ))) (adjoin (e i )) (adjoin (adjoin (e-i ))) (adjoin (adjoin (adjoin (e i )))) (adjoin (adjoin (adjoin ))) (adjoin (adjoin )) (adjoin ) ==> ( ) 7 8
Common Pattern #: cdr ing down a list Cdr ing and Cons ing Examples (define (list-ref lst n) (if (= n ) (first lst) (list-ref (rest lst) (- n )))) (define (copy lst) ; base case (adjoin (first lst) ; recursion (copy (rest lst))))) joe (list-ref joe ) (append (list ) (list )) ==> ( ) Strategy: copy list onto front of list. (+ (length (rest lst))))) 9 (define (append list list) (cond ((null? list) list) ; base (else (adjoin (first list) ; recursion (append (rest list) list))))) Common Pattern #: Transforming a List Common Pattern #: Filtering a List (define (square-list lst) (adjoin (square (first lst)) (square-list (rest lst))))) (define (double-list lst) (adjoin (* (first lst)) (double-list (rest lst))))) (define (filter pred lst) (cond ((null? lst) ) ((pred (first lst)) (adjoin (first lst) (filter pred (rest lst)))) (else (filter pred (rest lst))))) (define (map proc lst) (adjoin (proc (first lst)) (map proc (rest lst))))) (define (square-list lst) (map square lst)) (define (double-list lst) (map (lambda (x) (* x)) lst)) Common Pattern #: Accumulating Results Your Turn (define (add-up lst) (+ (first lst) (add-up (rest lst))))) (+ (length (rest lst))))) (define (mult-all lst) (* (first lst) (mult-all (rest lst))))) (define (accumulate op init lst) init (op (first lst) (accumulate op init (rest lst))))) (define (add-up lst) (accumulate + lst)) (define (accumulate op init lst) init (op (first lst) (accumulate op init (rest lst))))) Rewrite length as an accumulation (accumulate (lambda (item) ) lst))
(define make-point cons) (define point-x car) (define point-y cdr) To find the center of figure (define (centroid pts) (let ((total (length pts))) (/ (accumulate + (map point-x pts)) total) (/ (accumulate + (map point-y pts)) total)))) To shift a figure (define (shift pt offset) (- (point-x pt) (point-x offset)) (- (point-y pt) (point-y offset)))) (define (shift-figure pts offset) (map (lambda (pt) (shift pt offset)) pts)) 6 To rotate about the center (define (rotate pt) (- (point-y pt)) (point-x pt))) (define (rotate-figure pts) (let ((center (centroid pts))) (shift-figure (map rotate (shift-figure pts center)) (- (point-x center)) (- (point-y center)))))) To shift and clip (define (shift&clip pts offset) (filter (lambda (pt) (>= (point-x pt) )) (map (lambda (pt) (shift pt offset)) pts))) 7 8 Summary of part Data structures are built on contract of constructors and accessors Data structures have associated procedures for manipulation typically the recursive structure of the procedure mimics the recursive structure of the data object Building data structures Think about good organization for data Think about how procedures to manipulate structure will mimic organization of data Build and hide details of abstraction from use of abstraction, by relying on contract 9