Transcript Lecture 12

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)
12 ‫ שיעור‬- ‫מבוא מורחב‬
1
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 ‫ שיעור‬- ‫מבוא מורחב‬
2
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 ‫ שיעור‬- ‫מבוא מורחב‬
3
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 ‫ שיעור‬- ‫מבוא מורחב‬
4
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 ‫ שיעור‬- ‫מבוא מורחב‬
5
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 ‫ שיעור‬- ‫מבוא מורחב‬
6
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 ‫ שיעור‬- ‫מבוא מורחב‬
7
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 ‫ שיעור‬- ‫מבוא מורחב‬
Dispatch
on type
8
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 ‫ שיעור‬- ‫מבוא מורחב‬
9
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
Generic operations
types
Circle
Rectangle
Square
circumference circumference-circle circumference-rect circumference-square
area
area-circle
area-rect
area-square
fig-display
fig-display-circle
fig-display-rect
fig-display-square
12 ‫ שיעור‬- ‫מבוא מורחב‬
10
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)
(get key1 key2)  val/#f
Retrieves the value found in the
table under keys key1, key2
OR #f if the value is not found
12 ‫ שיעור‬- ‫מבוא מורחב‬
11
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 ‫ שיעור‬- ‫מבוא מורחב‬
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 ‫ שיעור‬- ‫מבוא מורחב‬
13
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 ‫ שיעור‬- ‫מבוא מורחב‬
14
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)))))
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
12 ‫ שיעור‬- ‫מבוא מורחב‬
15
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:
1. To add a representation, we only need to write
a package for the new representation without
changing generic procedures. (Execute the install
procedure once).
2. Changes are local.
3. No name clashes.
install-circle-package
install-rectangle-package
12 ‫ שיעור‬- ‫מבוא מורחב‬
..
16
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 ‫ שיעור‬- ‫מבוא מורחב‬
17
Message Passing (cont’)
Data Directed: in each operation we dispatch on type.
Message Passing: in each type we dispatch on operation.
Generic operations
types
Circle
Rectangle
Square
circumference circumference-circle circumference-rect circumference-square
area
area-circle
area-rect
area-square
fig-display
fig-display-circle
fig-display-rect
fig-display-square
12 ‫ שיעור‬- ‫מבוא מורחב‬
18
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 ‫ שיעור‬- ‫מבוא מורחב‬
19
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 ‫ שיעור‬- ‫מבוא מורחב‬
20
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 ‫ שיעור‬- ‫מבוא מורחב‬
21
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 ‫ שיעור‬- ‫מבוא מורחב‬
22
Writing procedures with a variable number
of parameters (dotted-tail notation)
At least two
parameters must
be passed
All other
parameters will
be passed in a
list named ‘z’
(define (proc x y . z) <body>)
This dot signifies that
proc accepts a variable
number of parameters
12 ‫ שיעור‬- ‫מבוא מורחב‬
23
Dotted-tail notation: examples
(define (proc x y . z) <body>)
(proc 1 2 3 4 5 6)
x  ?1
y?
2
z?
(3 4 5 6)
x  ?1
(proc 1 2)
y?
2
null
z?
(proc 1)
ERROR
12 ‫ שיעור‬- ‫מבוא מורחב‬
24
Dotted-tail notation: another example
(define (proc . z) <body>)
z  ?(1 2 3 4 5 6)
(proc 1 2 3 4 5 6)
(proc)
z  n?ull
(proc 1 (list 2 3))
z  (?1 (2 3))
12 ‫ שיעור‬- ‫מבוא מורחב‬
25
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) 
(count 0)  1
(count)  0
5
(length s)
(define (count . s) _________________)
12 ‫ שיעור‬- ‫מבוא מורחב‬
26
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) 
(lt 1000 1 10 0)  3
(lt 1)  0
(lt)  ERROR
2
lt returns the number of parameters
that are smaller than the first parameter.
12 ‫ שיעור‬- ‫מבוא מורחב‬
27
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 ‫ שיעור‬- ‫מבוא מורחב‬
28
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
(apply append '((1) (2) (3) (4)))
(apply expt '(2 4))
 (1 2 3 4)
 16
(apply list '(1 2 3 4 5))  (1 2 3 4 5)
12 ‫ שיעור‬- ‫מבוא מורחב‬
29
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)
(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.
12 ‫ שיעור‬- ‫מבוא מורחב‬
30
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)
Does not work!!
0
(add-abs (cdr l))
(+ (abs (car l)) _________________________)))
12 ‫ שיעור‬- ‫מבוא מורחב‬
31
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)
This is ok!
0
(apply add-abs (cdr l))
(+ (abs (car l)) _________________________)))
12 ‫ שיעור‬- ‫מבוא מורחב‬
32
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)
+ (map abs l)
(apply ________________________))
12 ‫ שיעור‬- ‫מבוא מורחב‬
33