SICP独習会〜抽象の壁(問題2.2〜2.3)〜

問題2.2

(define (make-segment x y)
  (cons x y))

(define (start-segment x) (car x))

(define (end-segment x) (cdr x))

(define (make-point a b)
  (cons a b))

(define (x-point x) (car x))

(define (y-point y) (cdr y))

(define (midpoint-segment a)
  (cons
   (/ (+ (x-point (start-segment a)) (x-point (end-segment a))) 2)
   (/ (+ (y-point (start-segment a)) (y-point (end-segment a))) 2)))

問題2.3

以下が最初に書いたソース。

(define rectangle-a
  (cons (make-segment (make-point 1 4) (make-point 1 -4))
	(make-segment (make-point -1 4) (make-point -1 -4))))

(define rectangle-b
  (cons (make-segment (make-point 3 1) (make-point 3 -1))
	(make-segment (make-point -3 1) (make-point -3 -1))))

; 線分の長さを求める手続き
; 2点からの線分の長さを求める方法を忘れた
(define (seg-lenght x)
  )

(define (rect-perimeter rect)
  (* 2 (+ (seg-lenght (car rect)) (seg-lenth (cdr (rect)))))

(define (rect-area rect)
  (* (seg-lenght (car rect)) (seg-lenght (cdr rect)))


 ここでは、とりあえず2種類の長方形を定義して書いてみた。その後、「2点からの線分の長さを求めるアルゴリズム」がわからなかったので、解答集みることに。解答集の答えと比較して気づいたことは、

  • セッター(構築子)、セレクター(選択子)がないと、抽象の壁を作れていない(オブジェクト指向的に言うと、実装部分が見えてカプセル化できていない)。
  • 抽象しきれないと、変更に弱いプログラムになる

ということである。(本にはバッチリ書いてありますが。「頭でなく体で理解した!!」という感じということで。)


 私の書いた長方形の周囲の長さを求める手続き「rect-perimeter」と、長方形の面積を求める手続き「rect-area」の


(car rect)
ように、直に(選択子を介さずに)データを取得すると、解答集のように、長方形のデータに変更があったときに、これらの手続きも変更しなくてはいけないことになる。これは、うまく抽象化をできていない例だと言える。


 2点から線分の長さを求めるアルゴリズムは、ここでは重要ではないので暇があったら復習しておくことにする。


 で、以上のことを踏まえて書き直したソースが以下の通り。

(define (def-rect a b)
  (cons a b))

;selector
(define (bottom rect)
  (car a))

;selector
(define (height rect)
  (cdr b))

(define (seg-lenght)
  )

(define (rect-perimeter rect)
  (* 2 (+ (seg-length bottom) (seg-lenght height)))

(define (rect-area rect)
  (* (seg-lenght bottom) (seg-lenght height)))

 仮に、解答集のように長方形を構成データを変更したとしても、セレクターを変更すれば良いだけですむようになる。