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?
首先借用 Exercise 2.2 的函式來表示矩形,我們已經有了線段的表示方法,那矩形就是2組平行且相等的線段,且鄰邊垂直。為了簡單起見,把矩形左下角的頂點座標設為(0, 0),且一條邊落在 x 軸上。然後採用矩形左邊的那條邊和對角線交點座標來確定一個矩形,同樣為了簡便起見,把交點座標設為(0, 0)。可以看出 make-point, x-point, y-point; make-segment, start-segment, end-segment; make-rect, make-rect-by-meeting-point; get-line-length, get-perimeter, get-area 是四層不同的函式,某一層的函式實現邏輯的改變,不會影響到其他層的呼叫。
; 用左下的頂點和經過該頂點的兩條鄰邊來確定一個矩形,為簡單起見,左下的頂點座標設為(0, 0)
; length, width 分別表示矩形的長和寬
(define (make-rect length width)
(let ((left-bottom (make-point 0 0)))
(cons (make-segment left-bottom (make-point (car left-bottom) (+ (cdr left-bottom) width))) ; 豎直的那條邊
(make-segment left-bottom (make-point (+ (car left-bottom) length) (cdr left-bottom)))))) ; 水平的那條邊
; 用矩形的對角線交點和左邊的邊來確定一個矩形,為簡單起見,對角線交點座標設為(0, 0)
; left-line 表示左邊的邊
(define (make-rect-by-meeting-point left-line)
(cons left-line (make-segment (start-segment left-line) (make-point (- 0 (x-point (start-segment left-line)))
(y-point (start-segment left-line))))))
; 用兩點間距離公式 d = sqrt(x^2 + y^2) 計算線段的長度
(define (get-line-length segment)
(sqrt (+ (square (- (x-point (end-segment segment))
(x-point (start-segment segment))))
(square (- (y-point (end-segment segment))
(y-point (start-segment segment)))))))
; 計算矩形的周長
(define (get-perimeter rect)
(* 2 (+ (get-line-length (car rect))
(get-line-length (cdr rect)))))
; 計算矩形的面積
(define (get-area rect)
(* (get-line-length (car rect))
(get-line-length (cdr rect))))
; 設定一個長為7寬為5的矩形
(define test-rect1 (make-rect 7 5))
(display "矩形test-rect1周長為:")
(display (get-perimeter test-rect1))
(newline)
(display "矩形test-rect1面積為:")
(display (get-area test-rect1))
(newline)
; 設定一個長為7寬為5的矩形
(define A (make-point -3.5 -2.5))
(define B (make-point -3.5 2.5))
(define left-line (make-segment A B))
(define test-rect2 (make-rect-by-meeting-point left-line))
(display "矩形test-rect2周長為:")
(display (get-perimeter test-rect2))
(newline)
(display "矩形test-rect2面積為:")
(display (get-area test-rect2))
(newline)
; 執行結果
矩形test-rect1周長為:24.000000282646763
矩形test-rect1面積為:35.00000070672435
矩形test-rect2周長為:24.000000282646763
矩形test-rect2面積為:35.00000070672435