330 likes | 432 Views
Lecture 12. Data directed programming Message passing dotted-tail notation & apply Section 2.4, pages 169-187 2.5.1,2.5.2 pages 187-197 (but with a different example). Multiple Representations of Abstract Data. Example: geometrical figures.
E N D
Lecture 12 Data directed programmingMessage passingdotted-tail notation & applySection 2.4, pages 169-1872.5.1,2.5.2 pages 187-197(but with a different example) מבוא מורחב - שיעור 12
Multiple Representations of Abstract Data Example: geometrical figures • We develop a package for handling geometrical figures • Each figure has a unique data representation • Want to support Generic Operations on figures, such as: • Compute figure area • Compute figure circumference • Print figure parameters, etc. מבוא מורחב - שיעור 12
Geometrical figures: interface Constructors: (make-rectangle width height) (make-circle radius) (make-square length) Rectangle implementation.. Circle implementation.. Square implementation.. Generic operations: (area figure) (circumference figure) (fig-display figure).. We will now see 3 alternative implementations… מבוא מורחב - שיעור 12
Implementation #1: tagged data • Main idea: add a tag (symbol) to every figure instance • Generic procedures dispatch on parameter type ('circle 2) ('square 1) ('rectangle 1 . 2) מבוא מורחב - שיעור 12
Attaching tags. (define (attach-tag type-tag contents) (cons type-tag contents)) (define (type-tag datum) (if (pair? datum) (car datum) (error "Bad tagged datum -- TYPE-TAG" datum))) (define (contents datum) (if (pair? datum) (cdr datum) (error "Bad tagged datum -- CONTENTS" datum))) מבוא מורחב - שיעור 12
Tagged data: rectangle implementation (define (make-rectangle width height) (attach-tag 'rectangle (cons width height))) (define (width rect) (car rect)) (define (height rect) (cdr rect)) (define (circumference-rect rect) (* 2 (+ (width rect) (height rect)))) (define (area-rect rect) (* (width rect) (height rect)))(define (fig-display-rect rect) (my-display "Rectangle: width, ” (width rect) ", height: " (height rect))) assume my-display takes any number of arguments and prints them. מבוא מורחב - שיעור 12
Tagged data: circle implementation (define (make-circle radius) (attach-tag 'circle (list radius))) (define PI 3.1415926) (define (radius circle) (car circle)) (define (circumference-circle circle) (* 2 PI (radius circle))) (define (area-circle circle) (let ((r (radius circle))) (* PI r r))) (define (fig-display-circle circle) (my-display “Circle: radius, ” (radius circle))) מבוא מורחב - שיעור 12
Dispatch on type Tagged data: generic operations (define (circumference fig) (cond ((eq? 'rectangle (type-tag fig)) (circumference-rect (contents fig))) ((eq? 'circle (type-tag fig)) (circumference-circle (contents fig) . .)) (define (area fig) (cond ((eq? 'rectange (type-tag fig)) (area-rect (contents fig))) ((eq? 'circle (type-tag fig)) (area-circle (contents fig) . .)) (define (fig-display fig) (cond ((eq? 'rectange (type-tag fig)) (fig-display-rectangle (contents fig))) ((eq? 'circle (type-tag fig)) (fig-display-circle (contents fig) . .)) מבוא מורחב - שיעור 12
The Difficulties The system is not additive/modular • The generic procedures must know about all types. • If we want to add a new type we need to • add it to each of the operations, • be careful with name clashes. (define (area fig) (cond ((eq? 'rectange (type-tag fig)) (area-rect (contents fig))) ((eq? 'circle (type-tag fig)) (area-circle (contents fig) . .)) מבוא מורחב - שיעור 12
types Circle Rectangle Square circumference-circle area-circle fig-display-circle circumference-rect area-rect fig-display-rect circumference area fig-display circumference-square area-square fig-display-square Generic operations Implementation #2: data directed programming • Main idea: work with a table. • Keep a pointer to the right procedure to call in the table, keyed by the operation/type combination מבוא מורחב - שיעור 12
Data-directed programming (Cont) Assume we have a global two dimensional table and the following operations on it: Adds val to the table, under keys key1, key2 (put key1 key2 val) Retrieves the value found in the table under keys key1, key2 OR #f if the value is not found (get key1 key2) val/#f מבוא מורחב - שיעור 12
Rectangle implementation (define (install-rectangle-package) ;; Implementation (define (width rect) (car rect)) (define (height rect) (cdr rect))(define (circumference rect) (* 2 (+ (width rect) (height rect)))) (define (area rect) (* (width rect) (height rect))) (define (fig-display rect) (my-display "Rectangle: width ,” (width rect) “, height " (height rect))) (define (make-rect width height) (attach-tag 'rectangle (cons width height))) ;; Interface to the rest of the system (put 'circumference 'rectangle circumference) (put 'area 'rectangle area) (put 'fig-display 'rectangle fig-display) (put 'make-fig 'rectangle make-rect) 'done) מבוא מורחב - שיעור 12
Circle implementation (define (install-circle-package) ;; Implementation (define PI 3.1415926) (define (radius circle) (car circle))(define (circumference circle) (* 2 PI (radius circle))) (define (area circle) (let ((r (radius circle)) (* PI r r))) (define (fig-display circle) (my-display “Circle: radius,” (radius rect))) (define (make-circle radius) (attach-tag 'circle (list radius))) ;; Interface to the rest of the system (put 'circumference 'circle circumference) (put 'area 'circle area) (put 'fig-display 'circle fig-display) (put 'make-fig 'circle make-circle) 'done) מבוא מורחב - שיעור 12
Generic procedures (define (circumference fig) (apply-generic 'circumference fig)) (define (area fig) (apply-generic 'area fig)) (define (fig-display fig) (apply-generic 'fig-display fig)) • Apply generic: • Locates the right procedure in the table • Calls it • Passes the figure-data as a parameter מבוא מורחב - שיעור 12
Get the type of the figure Locate the procedure that implements op on that type If there is such a procedure (get did not return #f) Call it and pass the figure-data as a parameter Apply-generic (define (apply-generic op arg) (let ((type (type-tag arg))) (let ((proc (get op type))) (if proc (proc (contents arg)) (error "No operation for this type -- APPLY-GENERIC" op type-tag))))) מבוא מורחב - שיעור 12
Summary: Data Directed programming Data Directed programming: The data (argument) triggers the right operation based on the data type. • Data Directed programming is more modular: • To add a representation, we only need to write • a package for the new representation without • changing generic procedures. (Execute the install • procedure once). • Changes are local. • No name clashes. • install-circle-package • install-rectangle-package • .. מבוא מורחב - שיעור 12
Implementation #3: Message Passing • Main idea: the figure is represented by a procedure • The procedure dispatches on the operation type Data Directed: Intelligent operations that work with different data types. Message Passing: Intelligent data types that support different operations. In message passing the idea is that the data gets a message that tells it which operation to invoke, and returns the result. מבוא מורחב - שיעור 12
Data Directed: in each operation we dispatch on type. types Message Passing: in each type we dispatch on operation. Circle Rectangle Square circumference-circle area-circle fig-display-circle circumference-rect area-rect fig-display-rect circumference-square area-square fig-display-square Message Passing (cont’) circumference area fig-display Generic operations מבוא מורחב - שיעור 12
Message passing style – rectangle figure The constructor has it all. (define (make-rectangle width height) (lambda (op) (cond ((eq? op 'area) (* height width)) ((eq? op 'circumference) (* 2 (+ width height))) ((eq? op 'fig-display) (my-display "Rectangle: width, ” width) “height, " height)) (else (error "Unknown op – MAKE-RECTANGLE" op))))) Another way to write this: (define (make-rectangle width height) (define (dispatch op) (cond ... ;; as above )) dispatch) מבוא מורחב - שיעור 12
Message passing style – circle figure The constructor has it all. (define (make-circle radius) (define PI 3.1415926) (lambda (op) (cond ((eq? op 'area) (* PI radius radius)) ((eq? op 'circumference) (* 2 PI radius)) ((eq? op 'fig-display) (my-display “Circle: radius ” radius)) (else (error "Unknown op – MAKE-CIRCLE" op))))) מבוא מורחב - שיעור 12
Generic operations and new apply-generic (define (circumference fig) (apply-generic 'circumference fig)) (define (area fig) (apply-generic 'area fig)) (define (fig-display fig) (apply-generic 'make-fig fig)) (define (apply-generic op arg) (arg op)) מבוא מורחב - שיעור 12
Summary: Message Passing • Additive • Avoids name-clashes problems • No need for a table • More difficult to extend for multi-parameter operations Message passing is the basis for Object Oriented Programming and we will discuss it again later. מבוא מורחב - שיעור 12
At least two parameters must be passed This dot signifies that proc accepts a variable number of parameters Writing procedures with a variable number of parameters (dotted-tail notation) All other parameters will be passed in a list named ‘z’ (define (proc x y . z) <body>) מבוא מורחב - שיעור 12
x ? y ? z ? 1 • (proc 1 2) 2 Dotted-tail notation: examples x ? y ? z ? 1 • (define (proc x y . z) <body>) • (proc 1 2 3 4 5 6) 2 (3 4 5 6) null ERROR • (proc 1) מבוא מורחב - שיעור 12
z ? • (proc) z ? • (proc 1 (list 2 3)) Dotted-tail notation: another example • (define (proc . z) <body>) • (proc 1 2 3 4 5 6) z ? (1 2 3 4 5 6) null (1 (2 3)) מבוא מורחב - שיעור 12
Dotted-tail notation: another example We want to implement a procedure (count…) that gets a variable number of parameters and returns their number (count 1 7 8 9 1) 5 (count 0) 1 (count) 0 (define (count . s) _________________) (length s) מבוא מורחב - שיעור 12
Dotted-tail notation: yet another example (define (lt x . y) (length (filter (lambda (z) (< z x)) y))) What does this procedure do ? (lt 1 7 8 9 1 0 -1) 2 (lt 1000 1 10 0) 3 (lt 1) 0 (lt) ERROR lt returns the number of parameters that are smaller than the first parameter. מבוא מורחב - שיעור 12
The builtin procedure Apply • Suppose we want to apply some procedure proc • but the parameters are available as a list (apply proc lst) will give the same result as (proc v1 v2 … vn) assuming lst is (v1 v2 … vn) מבוא מורחב - שיעור 12
Apply examples (apply * (list 1 2 3)) 6 (apply count (list 1 2 3)) 3 (apply lt (list 10 1 2 3 11 9)) 4 (1 2 3 4) (apply append '((1) (2) (3) (4))) (apply expt '(2 4)) 16 (1 2 3 4 5) (apply list '(1 2 3 4 5)) מבוא מורחב - שיעור 12
(define (general-map proc list1 . other-lists) (if (null? list1) '() (let ((lists (cons list1 other-lists))) (let ((firsts (simple-map car lists)) (rests (simple-map cdr lists))) (cons (apply proc firsts) (apply general-map (cons proc rests))))))) We use the names simple-map and general-map for clarity. The general procedure is actually called map. General map (define (f x y z) (+ x (* 2 y) (* 5 z))) (general-map f '(1 2 3) '(2 3 4) '(2 4 7)) (15 28 46) מבוא מורחב - שיעור 12
Another apply example Exercise: Implement a procedure, add-abs, that receives 0 or more numbers, and returns the sum of their absolute values. Examples:(add-abs) 0 (add-abs 1 -2 -3 4) 10 (define (add-abs . l) (if (null? l) 0 (+ (abs (car l)) _________________________))) Does not work!! (add-abs (cdr l)) מבוא מורחב - שיעור 12
Another apply example Exercise: Implement a procedure, add-abs, that receives 0 or more numbers, and returns the sum of their absolute values. Examples:(add-abs) 0 (add-abs 1 -2 -3 4) 10 (define (add-abs . l) (if (null? l) 0 (+ (abs (car l)) _________________________))) This is ok! (apply add-abs (cdr l)) מבוא מורחב - שיעור 12
Another apply example (cont) Exercise: Implement a procedure, add-abs, that receives 0 or more numbers, and returns the sum of their absolute values. Another solution (also using apply). (define (add-abs . l) (apply ________________________)) + (map abs l) מבוא מורחב - שיעור 12