SICP ex2-50

本次要求在之前三个类型的数据及存在相应的操作运算符的情况下将这些运算符统一化

采用的是data-directed的方式

需要注意的是要区分complex 内部的data-directed 以及运算符的data-directed

其他基本没有什么难度

;;put and get
(define (make-table) 
	(let ((local-table (list '*table*)))
	(define (lookup key-1 key-2)
		(let	((subtable (assoc key-1 (cdr local-table))))
			(if 	subtable
				(let	((record (assoc key-2 (cdr subtable))))
					(if record
						(cdr record)
						false))
				false)))
	(define (insert! key-1 key-2 value)
		(let	((subtable (assoc key-1 (cdr local-table))))
			(if subtable
				(let	((record (assoc key-2 (cdr subtable))))
					(if record
						(set-cdr! record value)
						(set-cdr! subtable
							  (cons (cons key-2 value) (cdr subtable)))))
						(set-cdr! local-table
							  (cons (list key-1 (cons key-2 value)) (cdr local-table)))))
		'OK)
	(define (dispatch m)
		(cond ((eq? m 'lookup-proc) lookup)
			((eq? m 'insert-proc) insert!)
			(else (error "Unknown operation -- TABLE" m))))
	dispatch))
(define operation-table (make-table))
(define get (operation-table 'lookup-proc))
(define put (operation-table 'insert-proc))

;;number
(define (num+ x y) (make-number (+ x y)))
(define (num- x y) (make-number (- x y)))
(define (num* x y) (make-number (* x y)))
(define (num/ x y) (make-number (/ x y)))
(define (make-number n) n)

;;rational
(define (denominator z) (cdr z))
(define (numerator z) (car z))
(define (rat+ x y)
	(make-rat 
		(+ (* (numerator x) (denominator y)) (* (numerator y) (denominator x)))
		(* (denominator x) (denominator y))))
(define (rat- x y)
	(make-rat
		(- (* (numerator x) (denominator y)) (* (numerator y) (denominator x)))
		(* (denominator x) (denominator y))))
(define (rat* x y)
	(make-rat
		(* (numerator x) (numerator y)) (* (denominator x) (denominator y))))
(define (rat/ x y)
	(make-rat
		(* (numerator x) (denominator y)) (* (numerator y) (denominator x))))
(define (make-rat x y)
	(define (reminder x y) (if (< x y) x (reminder (- x y) y)))
	(define (gcd x y)
		(let 	((small (if (< x y) x y))
			(big (if (< x y) y x)))
			(define (iter x y) 
				(if 
					(= 0 (reminder x y))
					y
					(iter x (- y 1))))
			(iter big small)))
	(let ((tmp (gcd x y)))
		(cons 'rational (cons (/ x tmp) (/ y tmp)))))




(put 'number 'add num+)
(put 'number 'sub num-)
(put 'number 'mul num*)
(put 'number 'div num/)
(put 'rational 'add rat+)
(put 'rational 'sub rat-)
(put 'rational 'mul rat*)
(put 'rational 'div rat/)

(define (type z) (if (number? z) 'number (car z)))
(define (content z) (if (number? z) z (cdr z)))
(define (add x y)
	(operate 'add x y))
(define (sub x y)
	(operate 'sub x y))
(define (mul x y)
	(operate 'mul x y))
(define (div x y)
	(operate 'div x y))

(define (operate op obj1 obj2)
	(cond
		((not (eq? (type obj1) (type obj2))) (error "Not same type"))
		(else
			((get (type obj1) op) (content obj1) (content obj2)))))


;;complex
;constructor
(define (complex-attach-type type content)
	(cons type content))
(define (complex-type z)
	(if
		(pair? z)
		(car z)
		(error "error data")))
(define (complex-content z)
	(if
		(pair? z)
		(cdr z)
		(error "error data")))
(define (rectangle? z)
	(eq? (complex-type z) 'rectangle))
(define (polar? z)
	(eq? (complex-type z) 'polar))
(define (make-rectangle x y)
	(complex-attach-type 'rectangle (cons x y)))
(define (make-polar r a)
	(complex-attach-type 'polar (cons r a)))

;;selector
(define (rectangle-real-part obj)
	(car obj))
(define (rectangle-imag-part obj)
	(cdr obj))
(define (rectangle-magnitude obj)
	(sqrt (+ (square (car obj)) (square (cdr obj)))))
(define (rectangle-angle obj)
	(atan (car obj) (cdr obj)))
(define (polar-real-part obj)
	(* (car obj) (cos (cdr obj))))
(define (polar-imag-part obj)
	(* (car obj) (sin (cdr obj))))
(define (polar-magnitude obj)
	(car obj))
(define (polar-angle obj)
	(cdr obj))

(put 'rectangle 'real-part rectangle-real-part)
(put 'polar 'real-part 	polar-real-part)
(put 'rectangle 'imag-part rectangle-imag-part)
(put 'polar 'imag-part polar-imag-part)
(put 'rectangle 'magnitude rectangle-magnitude)
(put 'polar 'magnitude polar-magnitude)
(put 'rectangle 'angle rectangle-angle)
(put 'polar 'angle polar-angle)

(define (complex-operate op obj)
	(let	((proc (get (complex-type obj) op)))
		(if
			(null? proc)
			(error "no this type" (list op obj))
			(proc (complex-content obj)))))


(define (real-part obj)
	(complex-operate 'real-part obj))
(define (imag-part obj)
	(complex-operate 'imag-part obj))
(define (magnitude obj)
	(complex-operate 'magnitude obj))
(define (angle obj)
	(complex-operate 'angle obj))


;;operator
(define (+c z1 z2)
	(make-complex (make-rectangle (+ (real-part z1) (real-part z2)) (+ (imag-part z1) (imag-part z2)))))
(define (-c z1 z2)
	(make-complex (make-rectangle (- (real-part z1) (real-part z2)) (- (imag-part z1) (imag-part z2)))))
(define (*c z1 z2)
	(make-complex (make-polar (* (magnitude z1) (magnitude z2)) (+ (angle z1) (angle z2)))))
(define (/c z1 z2)
	(make-complex (make-polar (/ (magnitude z1) (magnitude z2)) (- (angle z1) (angle z2)))))


(define (make-complex z)
	(cons 'complex z))
(define (make-rectangle-complex x y)
	(make-complex (make-rectangle x y)))
(define (make-polar-complex x y)
	(make-complex (make-polar x y)))
(put 'complex 'add +c)
(put 'complex 'sub -c)
(put 'complex 'mul *c)
(put 'complex 'div /c)
(put 'complex 'real-part real-part)
(put 'complex 'imag-part imag-part)
(put 'complex 'magnitude magnitude)
(put 'complex 'angle angle)
(define (c=zero? z)
	(and (= 0 (real-part z)) (= 0 (imag-part z))))
(define (r=zero? z)
	(and (= 0 (numerator z)) (not (= 0 (denominator z)))))
(define (n=zero? z)
	(= 0 z))
(put 'complex '=zero? c=zero?)
(put 'rational '=zero? r=zero?)
(put 'number '=zero? n=zero?)
(define (=zero? z)
	(let	((proc (get (type z) '=zero?)))
		(proc (content z))))


另外分析下magnitude 的实现原因,首先magnitude 调用了complex-operate这个函数并将op置为magnitude 然后在函数体中调用了complex-type获取了complex这样

就获取了实数的type 并定位到了magnitude 之后,又一次按之前的步骤进行调用,获取了rectangle-magnitude的函数,到此,成果实现要求

至于利用symbol?的原操作,为了实现格式统一,我们在type判断是number的之后自动返回'number即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值