SICPを読む(35) 問題2.2 - 2.3 オブジェクト指向っぽくなってきた。

オブジェクト指向っぽくなってきましたね。

今回は点と線、長方形の定義。グラフィックばっかりやってた時期があるので、馴染深い所です。

問題2.2

点と線を定義して、線の中点を出す問題。

;segment
(define (make-segment start end)
  (cons start end))
(define (start-segment s)
  (car s))
(define (end-segment s)
  (cdr s))
(define (midpoint-segment s)
  (make-point (/ (+ (x-point (start-segment s))
                    (x-point (end-segment s)))
                 2)
              (/ (+ (y-point (start-segment s))
                    (y-point (end-segment s)))
                 2)))

; point
(define (make-point x y)
  (cons x y))
(define (x-point p)
  (car p))
(define (y-point p)
  (cdr p))
(define (print-point p)
  (display (format "(~a, ~a)~%" (x-point p) (y-point p))))

(define segment1 (make-segment (make-point 1 2) (make-point 3 4)))
(define segment2 (make-segment (make-point 5 6) (make-point 7 8)))
(print-point (midpoint-segment segment1)) ; (2, 3)
(print-point (midpoint-segment segment2)) ; (6, 7)

肩慣らし。

中点の計算も抽象化した方が良かったかも。

修正
(define (midpoint-segment s)
  (define (mid f)
    (/ (+ (f (start-segment s))
          (f (end-segment s)))
       2))
  (make-point (mid x-point)
              (mid y-point)))

スッキリ!!

問題2.3

長方形の周囲の長さと、面積を出す問題。

まずは、((x1, y1),(x2, y2))の形。

; rect
(define (make-rect start end)
  (cons start end))
(define (start-rect r)
  (car r))
(define (end-rect r)
  (cdr r))

; width & height
(define (rect-width r)
  (abs (- (x-point (start-rect r))
          (x-point (end-rect r)))))
(define (rect-height r)
  (abs (- (y-point (start-rect r))
          (y-point (end-rect r)))))

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

(define rect (make-rect (make-point 1 2) (make-point 3 4)))
(rect-perimeter rect) ; 8
(rect-area rect) ; 4

最初、absしなかったので、マイナスになった(汗

共通する処理、rect-width,rect-heightを定義しました。もう1段階抽象化出来そう。

修正

; width & height
(define (size-calc f r)
  (abs (- (f (start-rect r))
          (f (end-rect r)))))
(define (rect-width r)
  (size-calc x-point r))
(define (rect-height r)
  (size-calc y-point r))

次。

((x, y), (width, height))の形。

; rect
(define (make-rect start size)
  (cons start size))
(define (start-rect r)
  (car r))
(define (size-rect r)
  (cdr r))

; width & height
(define (rect-width r)
  (x-point (size-rect r)))
(define (rect-height r)
  (y-point (size-rect r)))

(define rect (make-rect (make-point 1 2) (make-point 3 4)))
(rect-perimeter rect) ; 10
(rect-area rect) ; 6

こっちの方が好きかな。rect-width,rect-heightを定義しておいたので、計算をサボることが出来た!!

良好な抽象ってこんな感じ?

バグ

  • 割り切れないと分数になってしまった。(make-point 1.0 2.0)としたほうがいい。
  • 修正がめんどいのでそのまま(汗

まとめ

  • 長いけど、あっさり終わっちゃった。
  • 線は点とオフセット、点と角度と長さでも表すことが出来る。アルゴリズムによって変えよう。
  • クラスが無くてもクラスっぽい事は可能。
  • リストだけでも、今までとあんまり変わらない感じで定義出来ることがわかった。
  • これがどのように変化していくのか楽しみ。