SICP 問題 2.2(線分を作る)

休み時間中に問題文だけでも。。

問題

平面上の線分を表現する問題を考えよう。各線分は一対の点:始発点と終着点で表現されている
点を使って線分を表現する構成子 make-segment と選択子 start-segment と end-segment を定義せよ。
更に点は一対の数:x 座標と y 座標で表現することができる。
従ってこの表現を定義する構成子 make-point と選択子 x-point と y-point を規定せよ。
最後に選択子と構成子を使い、引数として線分をとり、中間点(座標が両端点の座標の平均である点)を返す手続き
midpoint-segment を定義せよ。その手続きを使ってみるには、点を印字する方法が必要である。

(define (print-point p)
  (newline)
  (display "(")
  (display (x-point p))
  (display ",")
  (display (y-point p))
  (display ")"))

解答

make-segment は、線分を作るために引数として2つの座標をとる手続きになる。
また、始点座標、終点座標を取得する手続きは1つの線分を引数にとる。
この考え方はそんなに難しかないだろう。

;線分生成手続き
(define (make-segment p0 p1)
  (cons p0 p1))

;始点座標を取得する手続き
(define (start-segment s)
  (car s))

;終点座標を取得する手続き
(define (end-segment s)
  (cdr s))

次は make-segment の引数となる座標が主役。
座標を生成する手続き make-point は、引数に x 座標、y 座標をとる。
x 座標、y 座標を取得する手続きは、それぞれ引数に座標をとる。

;座標生成手続き
(define (make-point x y)
  (cons x y))

;x 座標取得手続き
(define (x-point p)
  (car p))

;y 座標取得手続き
(define (y-point p)
  (cdr p))

最後、線分を引数にとってその中間点を返す手続き。
素直に書くとこんな感じ?

(define (midpoint-segment s)
  ;平均を取得する
  (define (average a b)
    (/ (+ a b) 2))
  ;座標をすべて取得
  (let* ((p0 (start-segment s))
	 (p1 (end-segment s)))
    (make-point (average (x-point p0) (x-point p1))
		(average (y-point p0) (y-point p1)))))

問題文には求めた中間点を表示する為の手続きが必要とあるが、ここで使っているデータは、単なるリストなので、gaucheを使うとそのまま表示できるので略。
さて、これらを使って線分の中間点を求めてみる。


gosh> (midpoint-segment (make-segment (make-point 0 0) (make-point 5 10)))
(5/2 . 5)
gosh> (midpoint-segment (make-segment (make-point -2 -3) (make-point 5 10)))
(3/2 . 7/2)
gosh> (midpoint-segment (make-segment (make-point -2 1) (make-point 5 10)))
(3/2 . 11/2)
gosh> (midpoint-segment (make-segment (make-point 5 10) (make-point -2 1)))
(3/2 . 11/2)
gosh>
い〜んじゃな〜い?