文章目录
SICP真是一本神书,看完第1章完全没有感觉到反感,虽然有难度,但是实在是很吸引人,马上开始第2章的征程。
2.1 代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| (define (gcd a b) (if (= b 0) a (gcd b (remainder a b)) )) (define (make-rat n d) (let ((g (gcd n d))) (cons (/ n g) (/ d g)))) (define (abs x) (if (< x 0) (- 0 x) x)) (define (make-rat-new n d) (let ((g (gcd n d))) (cond ((= n 0) (cons 0 1)) ((= d 0) (cons 1 0)) ((< (* n d) 0) (cons (- 0 (abs (/ n g))) (abs (/ d g)))) (else (cons (abs (/ n g)) (abs(/ d g))))) )) (define (numer x) (car x)) (define (denom x) (cdr x))
|
除去题目的要求,我还定义了0和无穷大2个值,可惜没有定义负无穷,偷懒了
2.2 这题并不是很麻烦
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| (define (print-point p) (newline) (display "(") (display (x-point p)) (display ",") (display (y-point p)) (display ")")) (define (make-point a b) (cons a b)) (define (x-point x) (car x)) (define (y-point x) (cdr x)) (define (make-segment a b) (cons a b)) (define (start-segment l) (car l)) (define (end-segment l) (cdr l)) (define (average x y) (/ (+ x y) 2)) (define (mid-segment l) (make-point (average (x-point (start-segment l)) (x-point (end-segment l))) (average (y-point (start-segment l)) (y-point (end-segment l))) ))
|
2.3 矩形的表示形式1,用左下角和右上角的点来表示矩形
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| (define (make-point a b) (cons a b)) (define (x-point x) (car x)) (define (y-point x) (cdr x)) (define (make-square a b) (cons a b)) (define (leftdown-square s) (car s)) (define (rightup-square s) (cdr s)) (define (leftup-square s) (make-point (x-point (leftdown-square s)) (y-point (rightup-square s))) ) (define (rightdown-square s) (make-point (x-point (rightup-square-square s)) (y-point (leftdown-square-square s))) ) (define (length-square s) (- (x-point (rightup-square s)) (x-point (leftdown-square s))) ) (define (width-square s) (- (y-point (rightup-square s)) (y-point (leftdown-square s))) ) (define (area-square s) (* (length-square s) (width-square s)) ) (define (perimeter-square s) (* 2 (+ (length-square s) (width-square s))) )
|
如果要有另一种表示的话,也可以用左上角和右下角来表示,重新定义上面的函数就好了,主要是length-square
和width-square
。但是这个问题,似乎另一种定义更好,就是定义左下角点和两个边的边长。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| (define (make-square x a b) (cons x (cons a b))) (define (leftdown-square s) (car s)) (define (rightup-square s) (let ((x-leftdown (x-point (car s))) (y-leftdown (y-point (car s)))) (make-point (+ x-leftdown (length-square s)) (+ y-leftdown (width-square s))) )) (define (leftup-square s) (let ((x-leftdown (x-point (car s))) (y-leftdown (y-point (car s)))) (make-point x-leftdown (+ y-leftdown (width-square s))) )) (define (rightdown-square s) (let ((x-leftdown (x-point (car s))) (y-leftdown (y-point (car s)))) (make-point (+ x-leftdown (length-square s)) y-leftdown) )) (define (length-square s) (car (cdr s)) ) (define (width-square s) (cdr (cdr s)) ) (define (area-square s) (* (length-square s) (width-square s)) ) (define (perimeter-square s) (* 2 (+ (length-square s) (width-square s))) )
|
测试代码不贴了
2.4 代码如下,并不麻烦,关键是理解lambda
1 2 3 4 5 6 7 8
| (define (cons x y) (lambda (m) (m x y))) (define (car z) (z (lambda (p q) p))) (define (cdr z) (z (lambda (p q) q)))
|
2.5 代码如下,借用1.16计算幂的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| (define (cons x y) (lambda (m) (m x y))) (define (car z) (z (lambda (p q) (fast-expt1 2 p)))) (define (cdr z) (z (lambda (p q) (fast-expt1 3 q)))) (define (fast-expt1 x n) (fast-expt1-iter 1 x n)) (define (fast-expt1-iter a x n) (cond ((= n 0) a) ((even? n) (fast-expt1-iter a (* x x) (/ n 2))) (else (fast-expt1-iter (* a x) (* x x) (/ (- n 1) 2)))))
|
2.6 定义one
和two
,把zero
带入到add-1
中就好了
1 2 3 4 5 6 7
| (define one (lambda (f) (lambda (x) (f x))) ) (define two (lambda (f) (lambda (x) (f (f x)))) )
|
可以猜测n=(lambda (f) (lambda (x) (f......<n个f> (f x))))
,那么加法就可以定义成
1 2
| (define (add m n) (lambda (f) (lambda (x) (<m个f> (<n个f> x)))) )
|
更加好一点的表述是
1 2
| (define (add m n) (lambda (f) (lambda (x) (m ((n f) x)))))
|
这题主要思路还是lambda的展开
2.7 感觉跟前面的定义线段的那题很相似
1 2 3 4 5
| (define (make-interval a b) (cons a b)) (define (lower-bound x) (car x)) (define (upper-bound x) (cdr x))
|
2.8 区间相减的代码如下
1 2 3 4 5 6 7
| (define (sub-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))))
|
2.9 假设区间a和区间b的宽度是la和lb,那么a+b和a-b的宽度都是la+lb。可以证明,这里不证了。乘法和除法的长度都是非线性的,会跟区间的上下限有关。
2.10 这题浪费时间在找assert
这个函数,其实错误处理还有error
什么的一系列,没有去研究了
1 2 3 4 5 6 7 8 9 10 11 12
| (define (<= x y) (or (< x y) (= x y))) (define (>= x y) (or (> x y) (= x y))) (define (contain-0 y) (and (<= 0 (upper-bound y)) (>= 0 (lower-bound y))) ) (define (div-interval x y) (assert (not (contain-0 y))) (mul-interval x (make-interval (/ 1.0 (upper-bound y)) (/ 1.0 (lower-bound y)))))
|
2.11 这题还比较有意思,区间a可以分3个情况:大于0、小于0、包含0;区间b也可以做这样的划分,这样就有3*3=9种不同的情况,代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| (define (<= x y) (or (< x y) (= x y))) (define (>= x y) (or (> x y) (= x y))) (define (contain-0 y) (and (<= 0 (upper-bound y)) (>= 0 (lower-bound y))) ) (define (gt-0 y) (and (> (lower-bound y) 0) (> (upper-bound y) 0)) ) (define (lt-0 y) (and (< (lower-bound y) 0) (< (upper-bound y) 0)) ) (define (mul-interval-new 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)))) (cond ((and (gt-0 x) (gt-0 y)) (make-interval p1 p4)) ((and (lt-0 x) (lt-0 y)) (make-interval p1 p4)) ((and (gt-0 x) (lt-0 y)) (make-interval p3 p2)) ((and (lt-0 x) (gt-0 y)) (make-interval p2 p3)) ((and (contain-0 x) (gt-0 y)) (make-interval p2 p4)) ((and (contain-0 x) (lt-0 y)) (make-interval p4 p1)) ((and (gt-0 x) (contain-0 y)) (make-interval p3 p4)) ((and (lt-0 x) (contain-0 y)) (make-interval p4 p1)) ((and (contain-0 x) (contain-0 y)) (make-interval (min p2 p4) (max p1 p4))) )))
|
2.12 代码如下
1 2 3 4 5 6 7 8 9
| (define (make-center-percent c p) (let ((w (abs (* c p)))) (make-interval (- c w) (+ c w)) )) (define (center i) (/ (+ (lower-bound i) (upper-bound i)) 2)) (define (percent i) (/ (/ (- (upper-bound i) (lower-bound i)) 2) (center i)))
|
2.13