(sicp33)m2.83~m2.84
疲れた><。
type-x>y?は作ってみたけど使わなかった。
(比較する度に階数を計算するのは効率が悪そうだし…)
;;m2.83 """ 順序 integer -> rational -> real -> complex """ (define (install-raise-package) (define (integer->rational i) (make-rational (contents i) 1)) (define (rational->real r) (make-real (/ (numer r) (denom r)))) (define (numer r) (car (contents r))) (define (denom r) (cdr (contents r))) (define (real->complex r) (make-complex-from-real-imag (contents r) 0)) (put 'raise 'integer integer->rational) (put 'raise 'rational rational->real) (put 'raise 'real real->complex)) (define (make-real n) (attach-tag 'real n)) (define (make-rat n d) (attach-tag 'rat (cons n d))) (define (make-integer i) (attach-tag 'integer i)) (define (my-raise n) (let1 proc (get 'raise (type-tag n)) (if proc (proc n) n))) (install-raise-package) (make-integer 3) (my-raise (make-integer 3)) (make-rat 3 2) (my-raise (make-rat 3 2)) (make-real 0.3333) (my-raise (make-real 0.333)) ;; 1:user> => (integer 3) ;; 2:user> => (rational 3 . 1) ;; 3:user> => (rat (3 . 2)) ;; 4:user> => (real 3/2) ;; 5:user> => (real 0.3333) ;; 6:user> => (complex rectangular 0.333 . 0) ;;たぶん、こんな感じでいいはず… ;;realのところで3/2がでているけど、これはgaucheの仕様っぽいのでいいや ;;(実数で表示する方法もあるのかな?) ;;m2.84 (define tower '(scheme-number rational real complex)) (define (type-level item) (define (look-up item tower count) (if (eq? (car tower) item) count (look-up item (cdr tower) (+ count 1)))) (unless tower (let1 tower '(scheme-number rational real complex))) (look-up item tower 0)) (define (type-x>y? x y) (unless tower (let1 tower '(scheme-number rational real complex))) (if (> (type-level x) (type-level y)) #t #f)) (type-x>y? 'complex 'complex) ;;#f (type-x>y? 'rational 'scheme-number) ;;#t ;;上のはintegerでした>< (put 'raise 'scheme-number (lambda (x) (make-rational x 1))) (define (apply-generic op . args) ;;もっとも高い型に揃える (define (raise-type args) (define (level x) (type-level (type-tag x))) (define (iter x hlv) (if (> hlv (level x)) (iter (my-raise x) hlv) x)) (let1 highestlv (fold-right (lambda (x mlv) (let1 xlv (level x) (if (> xlv mlv) xlv mlv))) 0 args) (fold-right (lambda (x y) (if (> highestlv (level x)) (cons (iter x highestlv) y) (cons x y))) '() args))) (let* ((type-tags (map type-tag args)) (proc (get op type-tags))) (if proc (apply proc (map contents args)) (let* ((new-args (raise-type args)) (new-type-tags (map type-tag new-args)) (new-proc (get op new-type-tags))) (if new-proc (apply new-proc (map contents new-args)) (error "methods is not found" (list op new-args))))))) ;;実行してみる前に、普通にcomplex同士のたし算ができるか確かめてみる (put 'add '(complex complex) (lambda (x y) (make-complex-from-real-imag (+ (real-part x) (real-part y)) (+ (imag-part x) (imag-part y))))) (real-part '(rectangular 3 . 4)) ;; 3 (let* ((f (lambda (x y) (make-complex-from-real-imag x y))) (args (list (f 3 4) (f 5 10)))) (apply (get 'add (map type-tag args)) (map contents args))) ;; gosh> (complex rectangular 8 . 14) (define sn (make-scheme-number 39)) (define c (make-complex-from-real-imag 3 4)) ;;型を変換できているか確認。 ;;(raise-type (list sn c)) ;; gosh> ((complex rectangular 39 . 0) (complex rectangular 3 . 4)) ;;できた。 (apply-generic 'add sn c) ;; gosh> (complex rectangular 42 . 4)