2.2 Exercise 2.2
The procedures for making and selecting from line segments and points are very similar –
just operations on pairs of their parts. make-segment and make-point are both calls
to cons, start-segment and x-point are both cars, and end-segment and
y-point are both cdrs.
(define (make-segment start end) | (cons start end)) |
|
(define (start-segment segment) | (car segment)) |
|
(define (end-segment segment) | (cdr segment)) |
|
(define (make-point x y) | (cons x y)) |
|
(define (x-point point) | (car point)) |
|
(define (y-point point) | (cdr point)) |
|
midpoint-segment is a simple operation relying on an average procedure that
is trivial enough to not include here.
(define (midpoint-segment s) | (let ((x (average (x-point (start-segment s)) | (x-point (end-segment s)))) | (y (average (y-point (start-segment s)) | (y-point (end-segment s))))) | (make-point x y))) |
|
To illustrate the power of these similar means of abstraction even more, we can
generalize the print-point procedure. The original as listed in the exercise
is as follows:
(define (print-point p) | (newline) | (display "(") | (display (x-point p)) | (display ",") | (display (y-point p)) | (display ")")) |
|
We could implement a separate print-segment procedure that calls print-point,
but I believe we can do better. print-point can be imagined as an instance
of a process doing the following things:
Print the pre-matter (in this case, a newline and "(")
Print the car of the pair
Print the between-matter (",")
Print the cdr of the pair
Print the end-matter (")")
Therefore, we could write a generalized print-pair procedure and implement
print-point, and also a new procedure print-segment, with it.
(define (print-pair pair pre between end inner-print) | (display pre) | (display (car pair)) | (display between) | (display (cdr pair)) | (display end)) |
|
However, while this will work perfectly well for reimplementing print-point,
it works less than well for making print-segment. It would be desirable to
have print-segment call print-point on each of its points, but print-pair
will necessarily call display on them, printing them with the environment’s
default representation for pairs. This will give a readable printout, but I believe
we should do better. This can be done by supplying one more argument to print-pair,
an inner-print procedure that is called to print the car and cdr of the pair
And so we get the actual print-pair procedure:
(define (print-pair pair pre between end inner-print) | (display pre) | (inner-print (car pair)) | (display between) | (inner-print (cdr pair)) | (display end)) |
|
And with this, we can make print-point and print-segment:
(define (print-point p) | (print-pair p "(" "," ")" display)) |
|
(define (print-segment s) | (print-pair s "" " -> " "" print-point)) |
|
There is another benefit that we can get out of this. Suppose we implemented
print-segment using the first version of print-point given in the book.
Each point would have a newline before it, necessarily and always. If we wanted
to change this (say, to print a segment on one line), we would have to write a
new print-point procedure. This is significantly easier to handle with the new
print-pair procedure – we can simply supply newlines to be printed wherever
we want. The problem could be solved like so:
(define (println-segment s) | (print-pair s "" " -> " "\n" print-point)) |
|
It would be even better if the cars and cdrs of the pairs sent to
print-pair knew how to print themselves, but that is getting beyond the scope
of the exercise.