2
\$\begingroup\$

From SICP:

Exercise 2.2

Consider the problem of representing line segments in a plane. Each segment is represented as a pair of points: a starting point and an ending point. Define a constructor make-segment and selectors start-segment and end-segment that define the representation of segments in terms of points. Furthermore, a point can be represented as a pair of numbers: the x coordinate and the y coordinate. Accordingly, specify a constructor make-point and selectors x-point and y-point that define this representation. Finally, using your selectors and constructors, define a procedure midpoint-segment that takes a line segment as argument and returns its midpoint (the point whose coordinates are the average of the coordinates of the endpoints). To try your procedures, you'll need a way to print points:

(define (print-point p)
  (newline)
  (display "(")
  (display (x-point p))
  (display ",")
  (display (y-point p))
  (display ")"))

I wrote the following solution:

(define (make-segment a b) (cons a b))
(define (start-segment l) (car l))
(define (end-segment l) (cdr l))

(define (make-point x y) (cons x y))
(define (x-point p) (car p))
(define (y-point p) (cdr p))

(define (sum . l) (if (zero? (length l)) 0 (+ (car l) (apply sum (cdr l)))))
(define (average . l) (/ (apply sum l) (length l)))

(define (midpoint seg)
  (make-point (average (x-point (start-segment seg)) 
                       (x-point (end-segment seg)))
              (average (y-point (start-segment seg))
                       (y-point (end-segment seg)))))

(define (print-point p)
  (newline)
  (display "(")
  (display (x-point p))
  (display ",")
  (display (y-point p))
  (display ")"))

(define seg-1 (make-segment (make-point 3 4)
                            (make-point 8 10)))
(print-point (midpoint seg-1))

What do you think?

\$\endgroup\$
2
\$\begingroup\$

Your definitions of make-segment and make-point can be simply bound to cons; you may do the same for accessors.

(define make-segment cons)
(define start-segment car)
(define end-segment cdr)

(define make-point cons)
(define x-point car)
(define y-point cdr)

Your definition of sum is similar to how + works. You may use + instead in your definition of average.

(define (average . l) (/ (apply + l) (length l)))

Notice the repetition of code in your definition of midpoint--you create a new point out of the averages of each coordinate of the two end-points that describe the line segment. You may abstract out the calculation of averages either by writing your own helper function or by using the built-in map function, like so:

(define point->coordinate-accessors (list x-point y-point))
(define (midpoint seg)
  (apply make-point (map (lambda (point->coordinate)
                           (average (point->coordinate (start-segment seg))
                                    (point->coordinate (end-segment seg))))
                         point->coordinate-accessors)))

This definition is general enough to handle midpoint calculation in as many dimensions as handled by make-point and point->coordinate-accessors.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.