Решение упражнения 2.3 из SICP
Я рассмотрю это упражнение в несколько упрощенной форме. Будем считать, что прямоугольники ориентированы вдоль осей координат. Более общий случай рассмотрен, например, на SICP Wiki, но и упрощенного варианта вполне достаточно для демонстрации основных идей.
При любом представлении прямоугольника его периметр равен удвоенной сумме длин смежных сторон, а площадь равна произведению длин смежных сторон:
(define (rectangle-perimeter rectangle) (* 2 (+ (rectangle-width rectangle) (rectangle-height rectangle))))
(define (rectangle-area rectangle) (* (rectangle-width rectangle) (rectangle-height rectangle)))
Первый способ представления прямоугольников - это представление двумя противоположными угловыми точками (я их назвал левой верхней и правой нижней, но это не принципиально). Это представление задается так:
(define (make-rectangle topleft bottomright) (cons topleft bottomright))
(define (rectangle-topleft rectangle) (car rectangle))
(define (rectangle-bottomright rectangle) (cdr rectangle))
(define (rectangle-width rectangle) (abs (- (x-point (rectangle-topleft rectangle)) (x-point (rectangle-bottomright rectangle)))))
(define (rectangle-height rectangle) (abs (- (y-point (rectangle-topleft rectangle)) (y-point (rectangle-bottomright rectangle)))))
Второй способ представления прямоугольников - заданием левого верхнего угла (точки), а также ширины и длины). Это представление задается так:
(define (make-rectangle topleft width height) (cons topleft (cons width height)))
(define (rectangle-topleft rectangle) (car rectangle))
(define (rectangle-width rectangle) (car (cdr rectangle)))
(define (rectangle-height rectangle) (cdr (cdr rectangle)))
Как видим, процедуры вычисления периметра и площади остаются неизменными при переходе от одного представления к другому. Они не изменятся и в случае, когда мы будем использовать более сложные представления для прямоугольников, ориентированных на плоскости произвольным образом.
Comments
Comment from gorilych
Date: July 17, 2008, 2:02 pm
Как я понял, смена представления не должна затрагивать интерфейсов основных функций, а здесь меняется набор и значения параметров для процедуры make-rectangle
Тем не менее, основное требование (”одни и те же процедуры вычисления периметра и площади работали с любым из Ваших представлений”) выполнено ибо rectangle-perimeter и rectangle-area не используют конструктор.
Comment from eugene0
Date: January 21, 2009, 9:53 am
На мой взгляд, это не очень хорошее решение, т.к. ваши определения не могут сосуществовать в одной системе, а значит практической пользы от такого полиморфизма нет. Я бы сделал так:
(define (make-recatngle1 topleft bottomright)
(cons (topleft bottomright))
(define (make-rectangle2 topleft width height)
(cons (topleft
(make-point (+ (x-point topleft) width) (+ (y-point topleft) height)))
Остальное так же, как у вас в первом варианте представления. Теперь остальные функции для работы с прямоугльниками будут едиными, т.к. внутреннее представление одно, несмотря на то, что сконструировать его можно двумя способами.
Write a comment