Exercise 2.3. Implement a representation for rectangles in a plane. (Hint: You may want to make use of exercise 2.2.) In terms of your constructors and selectors, create procedures that compute the perimeter and the area of a given rectangle. Now implement a different representation for rectangles. Can you design your system with suitable abstraction barriers, so that the same perimeter and area procedures will work using either representation?
要实现一个平面矩形的表示,我们只需要点就可以,并且,我们就只需要矩形的对角的 2 个点就可以确定矩形的位置和大小。
首先定义矩形上的操作:
;; first, define the operation
(define (perimeter retangle)
(+ (* 2 (length retangle))
(* 2 (width retangle))))
(define (area retangle)
(* (length retangle)
(width retangle)))
根据这些操作,我们需要定义矩形的 selector 和 constructor:
;;; retangle
;; A +-------------------+ D
;; | |
;; | |
;; B +-------------------+ C
(define (make-retangle A C)
(let ((B (make-point (x-point A) (y-point C)))
(D (make-point (x-point C) (y-point A))))
(list A B C D)))
(define (length retangle)
(let ((A (car retangle))
(D (cadddr retangle)))
(points-len A D)))
(define (width retangle)
(let ((A (car retangle))
(B (cadr retangle)))
(points-len A B)))
最后是最基础的点的表示:
;;; get length between two points
(define (points-len p1 p2)
(let ((len1 (abs (- (x-point p1) (x-point p2))))
(len2 (abs (- (y-point p1) (y-point p2)))))
(sqrt (+ (* len1 len1)
(* len2 len2)))))
;;; point data structure
(define (make-point x y)
(cons x y))
(define (x-point point)
(car point))
(define (y-point point)
(cdr point))
在测试中,我们选择点 (1, 3) (8, 1) 作为矩形的对角的两个点,对这个矩形进行周长和面积的测试。
(load "../testframe.scm")
(let* ((A (make-point 1 3))
(C (make-point 8 1))
(ret (make-retangle A C)))
(begin
(assert= 18 (perimeter ret))
(assert= 14 (area ret))))