SICPゼミ第5回
練習問題2.1
正と負の両方の引数を扱うことができる改良版make-rat を定義せよ。make-rat は符号を正規化し、正の有理数であれば分子と分母の両方が正となり、負の有理数であれば分子のみが負になるようにする。
(define (numer x) (car x)) (define (denom x) (cdr x)) (define (print-rat x) (newline) (display (numer x)) (display "/") (display (denom x))) (define (gcd a b) (if (= b 0) a( gcd b (remainder a b)))) (define (make-rat n d) (let ((g (cond ((and (< n 0) (< d 0)) (* -1 (gcd (* -1 n) (* -1 d)))) ((< n 0) (gcd (* -1 n) d)) ((< d 0) (* -1 (gcd n (* -1 d)))) (else (gcd n d))))) (cons (/ n g) (/ d g))))
by pine
(define (make-rat n d) (let ( (g (gcd (abs n) (abs d))) (sgn (/ (* n d) (abs (* n d)))) ) (cons sgn (cons (/ (abs n) g) (/ (abs d) g))) ) ) (define (numer x) (car (cdr x))) (define (denom x) (cdr (cdr x))) (define (sig x) (car x)) (define (print-rat x) (cond ((= (sig x) 1) (newline) (display (numer x)) (display "/") (display (denom x)) ) (else (newline) (display "-") (display (numer x)) (display "/") (display (denom x)) ) ) )
by どりきゃす
2.1.2 抽象化の壁
壁(barrier)とか言ってるけど階層(layer)だよね.gcdをアクセス時までに遅らせる理由がわからんけど.
練習問題2.2
平面上の線分を表現するという問題について考える。
それぞれの線分は、始点と終点という点のペアとして表す。コンストラクタmake-segment とセレクタstart-segment, end-segmentを定義せよ。さらに、点はx 座標とy 座標という数値のペアとして表現できる。最後に、定義したセレクタとコンストラクタによって、線分を引数として取りその中点(両端点の座標を平均した座標を持つ点) を返すmidpoint-segment 手続きを定義せよ
(define (make-segment s e) (cons s e)) (define (start-segment x) (car x)) (define (end-segment x) (cdr x)) (define (make-point x y) (cons x y)) (define (x-point p) (car p)) (define (y-point p) (cdr p)) (define (midpoint-segment s) (cons (/ (+ (x-point (start-segment s)) (x-point (end-segment s))) 2) (/ (+ (y-point (start-segment s)) (y-point (end-segment s))) 2))) (define (print-point p) (newline) (display "(") (display (x-point p)) (display ",") (display (y-point p)) (display ")"))
実行結果
gosh> (print-point (midpoint-segment (make-segment (make-point 0 2) (make-point 2 4)))) (1,3)#<undef>
練習問題2.3
長方形作れオラ
(define (make-rect x y c r) (cons c (cons r (cons x y)))) (define (get-column-length r) (car r)) (define (get-row-length r) (car(cdr r))) (define (get-basepoint r) (cdr (cdr r))) (define (length-of-outline r) (+ (* 2 (get-row-length r)) (* 2 (get-column-length r)))) (define (area r) (* (get-row-length r) (get-column-length r)))
点クラスの定義
(define (make-point x y) (cons x y)) (define x-point car) (define y-point cdr)
長方形の二つの定義
(define (make-rect x y) (cons x y) ) (define left-up car) (define right-down cdr)
対角線上の二つの頂点を保存
(define (make-rect tate yoko hidariue) (cons hidariue (cons tate yoko))) (define left-up car) (define (right-down x) (make-point (+ (x-point (left-up x)) (cdr (cdr x))) (- (y-point (left-up x)) (car (cdr x))) ))
左上の点、縦の長さ、横の長さを保存
どっちの場合でも次のように長さ、面積を求められる。
(define (len-tate x) (abs (- (y-point (left-up x)) (y-point (right-down x)))) ) (define (len-yoko x) (abs (- (x-point (left-up x)) (x-point (right-down x))))) (define (length x) (* 2 (+ (len-yoko x) (len-tate x)))) (define (measure x) (* (len-yoko x) (len-tate x)))
by どりきゃす
練習問題2.4
練習問題2.5
(define (cons_ x y) (* (fast-expt 2 x) (fast-expt 3 y))) (define (how-many-divide? x n) (define (iter x n res) (cond ((= 0 (remainder x 3)) (iter (/ x 3) n (+ res 1))) (else res) ) ) (iter x n 0) ) (define (car_ x) (how-many-divide? x 2)) (define (cdr_ x) (how-many-divide? x 3))
練習問題2.6
練習問題2.7
区間のコンストラクタの定義は以下のようになる。
(define (make-interval a b) (cons a b))
セレクタupper-bound とlower-bound を定義し、実装を完成させよ。
(define (make-interval a b) (cons a b)) (define upper-bound car) (define lower-bound cdr)
練習問題2.8
引き算の手続きsub-interval を定義せよ。
(define (sub-interval a b) (make-interval (- (upper-bound a) (lower-bound b)) (- (lower-bound a) (upper-bound b))))
ついでに
(define (print-interval a) (display "(") (display (lower-bound a)) (display "~") (display (upper-bound a)) (display ")"))
実行結果
gosh> (print-interval (sub-interval (make-interval 3 2) (make-interval 4 1))) (-2~2)#<undef>