Posted at

# SICP読書録 #18 2.1.2 抽象化の壁-練習問題 2.3

hiroshi-manabe様の日本語訳を使わせてもらいます。

## 2.1.2 抽象化の壁

_.scm

```(define (make-rat n d) (cons n d))
(define (numer x)
(let ((g (gcd (car x) (cdr x))))
(/ (car x) g)))
(define (denom x)
(let ((g (gcd (car x) (cdr x))))
(/ (cdr x) g)))
```

これを使ってたプログラムは変更しなくてすむのだ。

### 練習問題 2.2

まずは点を表現できなくてはいけないだろう。コンストラクタとXY座標のセレクタ、そして表示を行う手続きを作る。

_.scm

```(define (make-point x y)
(cons x y))
(define (x-point p)
(car p))
(define (y-point p)
(cdr p))
(define (print-point p)
(print "(" (x-point p) "," (y-point p) ")"))
```

これで、線分のコンストラクタ、始点と終点のセレクタを作れる。

_.scm

```(define (make-segment s e)
(cons s e))
(define (start-segment sg)
(car sg))
(define (end-segmeint sg)
(cdr sg))
```

では、線分の中点を返す手続きを作ろう。

_.scm

```(define (midpoint-segment sg)
(define (average a b) (/ (+ a b) 2))
(let ((s (start-segment sg))
(e (end-segment sg)))
(make-point (average (x-point s) (x-point e))
(average (y-point s) (y-point e)))))
```

_.scm

```gosh> (define sg (make-segment (make-point 10 20) (make-point 110 120)))
gosh> (print-point (midpoint-segment sg))
(60,70)
```

### 練習問題 2.3

_.scm

```(define (make-rectangle p1 p2)
(cons p1 p2))
(define (width-rectangle r)
(abs (- (x-point (car r)) (x-point (cdr r)))))
(define (height-rectangle r)
(abs (- (y-point (car r)) (y-point (cdr r)))))
```

_.scm

```(define (perimeter-rectangle r)
(* 2 (+ (width-rectangle r) (height-rectangle r))))
(define (area-rectangle r)
(* (width-rectangle r) (height-rectangle r)))
```

_.scm

```gosh> (define r (make-rectangle (make-point 10 10) (make-point 110 210)))
gosh> (width-rectangle r)
100
gosh> (height-rectangle r)
200
gosh> (perimeter-rectangle r)
600
gosh> (area-rectangle r)
20000
```

さて、内部表現を始点と終点ではなく、幅と高さのペアとするように修正してみよう。

_.scm

```(define (make-rectangle p1 p2)
(cons (abs (- (x-point p1) (x-point p2)))
(abs (- (y-point p1) (y-point p2)))))
(define (width-rectangle r)
(car r))
(define (height-rectangle r)
(cdr r))
```

こちらのバージョンでも、先ほどの周囲長と面積を求める手続きは修正の必要なく、そのまま使える。