2.1.1 Example: Arithmetic Operations for Rational Numbers

今までは手続きの抽象化、ここからはデータの抽象化。
リンク先のサイトの Figure 2.1: Data-abstraction barriers in the rational-number package が分かりやすい。

  • Programs that use rational numbers
  • (Rational numbers in problem domain)
  • add-rat sub-rat ...
  • (Rational numbers as numerators and denominators)
  • make-rat numer denom
  • (Rational numbers as pairs)
  • cons car cdr

前準備

(define (add-rat x y)
  (make-rat (+ (* (numer x) (denom y))
               (* (numer y) (denom x)))
            (* (denom x) (denom y))))
(define (sub-rat x y)
  (make-rat (- (* (numer x) (denom y))
               (* (numer y) (denom x)))
            (* (denom x) (denom y))))
(define (mul-rat x y)
  (make-rat (* (numer x) (numer y))
            (* (denom x) (denom y))))
(define (div-rat x y)
  (make-rat (* (numer x) (denom y))
            (* (denom x) (numer y))))
(define (equal-rat? x y)
  (= (* (numer x) (denom y))
     (* (numer y) (denom x))))

(define (make-rat n d)
  (let ((g (gcd n d)))
    (cons (/ n g) (/ d g))))

(define (numer x) (car x))

(define (denom x) (cdr x))

(define (print-rat x)
  (newline)
  (display (numer x))
  (display "/")
  (display (denom x)))

2.1

(define (make-rat n d)
  (define (sign x)
    (cond ((positive? x)  1)
          ((negative? x) -1)
          (else           0)))
  (let ((g (* (gcd n d) (sign d))))
    (cons (/ n g) (/ d g))))

2.2

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

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

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

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

(define (make-segment s e)
  (cons s e))

(define (start-segment s)
  (car s))

(define (end-segment s)
  (cdr s))

(define (midpoint-segment s)
  (let ((start (start-segment s))
        (end   (end-segment s)))
    (make-point (/ (+ (x-point start) (x-point end)) 2)
                (/ (+ (y-point start) (y-point end)) 2))))

2.3

(define (make-rect-tb top bottom)
  (cons top bottom))

(define (top-rect r)
  (car r))

(define (bottom-rect r)
  (cdr r))

(define (make-rect-lr left right)
  (cons left right))

(define (left-rect r)
  (car r))

(define (right-rect r)
  (cdr r))

(define (length-segment s)
  (define (square x) (expt x 2))
  (let ((start (start-segment s))
        (end   (end-segment s)))
    (sqrt (+ (square (- (x-point start) (x-point end)))
             (square (- (y-point start) (y-point end)))))))

(define (perimeter-rect-lr r)
  (* (+ (length-segment (left-rect r))
        (length-segment (right-rect r)))
     2))

(define (perimeter-rect-tb r)
  (* (+ (length-segment (top-rect r))
        (length-segment (bottom-rect r)))
     2))

(perimeter-rect-lr
  (make-rect-lr 
    (make-segment
      (make-point 1 2)
      (make-point 4 5))
    (make-segment
      (make-point 10 15)
      (make-point 3 7))))

2.4 (cons)

(define (%cons x y)
  (lambda (m) (m x y)))

(define (%car z)
  (z (lambda (x y) x)))

(define (%cdr z)
  (z (lambda (x y) y)))

2.5 (cons)

(define (%cons a b)
  (* (expt 2 a) (expt 3 b)))

(define (pow-of x y)
  (if (zero? (remainder x y))
    (+ 1 (pow-of (/ x y) y))
    0))

(define (%car c)
  (pow-of c 2))

(define (%cdr c)
  (pow-of c 3))

2.6 (チャーチ数)

前もやったな。

(define zero (lambda (f) (lambda (x) x)))

(define (add-1 n)
  (lambda (f) (lambda (x) (f ((n f) x)))))

; (add-1 zero)
; => (lambda (f) (lambda (x) (f (((lambda (f) (lambda (x) x)) f) x))))
; => (lambda (f) (lambda (x) (f (             (lambda (x) x)     x))))
; => (lambda (f) (lambda (x) (f                           x       )))
(define one (lambda (f) (lambda (x) (f x))))

; (add-1 one)
; => (lambda (f) (lambda (x) (f (((lambda (f) (lambda (x) (f x))) f) x))))
; => (lambda (f) (lambda (x) (f (             (lambda (x) (f x))     x))))
; => (lambda (f) (lambda (x) (f                           (f x)        )))
(define two (lambda (f) (lambda (x) (f (f x)))))

(define (to-number n)
  ((n (lambda (x) (+ x 1))) 0))

(define (add n m)
  (lambda (f) (lambda (x) ((m f) ((n f) x)))))

(define (mul n m)
  (lambda (f) (n (m f))))

2.1.4 Extended Exercise: Interval Arithmetic 前準備

区間演算。

(define (add-interval x y)
  (make-interval (+ (lower-bound x) (lower-bound y))
                 (+ (upper-bound x) (upper-bound y))))

(define (mul-interval x y)
  (let ((p1 (* (lower-bound x) (lower-bound y)))
        (p2 (* (lower-bound x) (upper-bound y)))
        (p3 (* (upper-bound x) (lower-bound y)))
        (p4 (* (upper-bound x) (upper-bound y))))
    (make-interval (min p1 p2 p3 p4)
                   (max p1 p2 p3 p4))))

(define (div-interval x y)
  (mul-interval x 
                (make-interval (/ 1.0 (upper-bound y))
                               (/ 1.0 (lower-bound y)))))

2.7

(define (make-interval l u) (cons l u))

(define (lower-bound i) (car i))

(define (upper-bound i) (cdr i))

2.8

(define (sub-interval x y)
  (make-interval (- (lower-bound x) (lower-bound y))
                 (- (upper-bound x) (upper-bound y))))

2.9

(define (width-interval i)
  (/ (- (upper-bound i) (lower-bound i)) 2))

2.10

(define (div-interval x y)
  (if (and (not (positive? (lower-bound y)))
           (not (negative? (upper-bound y))))
    (error "div-interval: y spans zero")
    (mul-interval x 
                  (make-interval (/ 1.0 (upper-bound y))
                                 (/ 1.0 (lower-bound y))))))

2.11

(define (mul-interval x y)
  (if (and (not (positive? (lower-bound x)))
           (not (negative? (upper-bound x)))
           (not (positive? (lower-bound y)))
           (not (negative? (upper-bound y))))
    (let ((p1 (* (lower-bound x) (lower-bound y)))
          (p2 (* (lower-bound x) (upper-bound y)))
          (p3 (* (upper-bound x) (lower-bound y)))
          (p4 (* (upper-bound x) (upper-bound y))))
      (make-interval (min p1 p2 p3 p4)
                     (max p1 p2 p3 p4)))
    (let ((p1 (* (lower-bound x) (lower-bound y)))
          (p2 (* (upper-bound x) (upper-bound y))))
      (make-interval (min p1 p2)
                     (max p1 p2)))
    ))

自信なし。

2.12

(define (make-center-width c w)
  (make-interval (- c w) (+ c w)))

(define (center i)
  (/ (+ (lower-bound i) (upper-bound i)) 2))

(define (width i)
  (/ (- (upper-bound i) (lower-bound i)) 2))
(define (make-center-percent c p)
  (make-center-width c (* c p 0.01)))

(define (percent i)
  (* (/ (width i) (center i)) 100))

2.13 - 2.16

桁落ちとかそういうことかな。数学的な話。省略