1. 程式人生 > >SICP習題解答2.1-2.6

SICP習題解答2.1-2.6

ex2.1-2.4

#lang racket

; exercise 2.1
(define (make-rat n d)
  (define g (gcd n d))
  (let ((g1 (if (< d 0) (- g) g)))
    (cons (/ n g1) (/ d g1))))
(define (gcd a b)  ;; 返回正最大公約數
  (if (= b 0)
      (if (< a 0) (- a) a)
      (gcd b (remainder a b))))

; exercise 2.2
(define (make-segment s e)
  (cons s e))
(define (start-segment seg)
  (car seg))
(define (end-segment seg)
  (cdr seg))
(define (make-point x y)
  (cons x y))
(define (x-point p)
  (car p))
(define (y-point p)
  (cdr p))
(define (midpoint-segment seg)
  (let ((a (start-segment seg))
        (b (end-segment seg)))
    (make-point (/ (+ (x-point a) (x-point b)) 2)
                (/ (+ (y-point a) (y-point b)) 2))))
(define (print-point p)
  (newline)
  (display "(")
  (display (x-point p))
  (display ",")
  (display (y-point p))
  (display ")"))
(print-point (midpoint-segment (make-segment (make-point 32 21) (make-point 45 10))))

; exercise 2.3
;; 假設矩形的邊平行於座標軸,然後用左下點+右上點確定一個矩形
(define (make-rect left-bottom right-top)
  (cons left-bottom right-top))
(define (left-bottom rect) (car rect))
(define (right-top rect) (cdr rect))
(define (width-rect rect)
  (- (x-point (right-top rect))
     (x-point (left-bottom rect))))
(define (height-rect rect)
  (- (y-point (right-top rect))
     (y-point (left-bottom rect))))

(define (perimeter-rect rect)
  (* (+ (width-rect rect) (height-rect rect)) 2))
(define (area-rect rect)
  (* (width-rect rect) (height-rect rect)))

(define r (make-rect (make-point 1 2) (make-point 3 6)))
(perimeter-rect r)
(area-rect r)
;; 其他定義一個矩形方法有很多,例如左下點+長寬等

; exercise 2.4
(define (cdr z)
  (z (lambda (p q) q)))

ex2.5

#lang racket

; exercise 2.5
(define (cons a b)
  (* (pow 2 a) (pow 3 b)))
(define (car x) (f x 2))
(define (cdr x) (f x 3))

(define (pow base exp)
  (define (iter cur res)
    (if (= 0 cur)
        res
        (iter (- cur 1) (* base res))))
  (iter exp 1))
(define (f x base)
  (define (iter res)
    (if (= 0 (remainder x (pow base res)))
        (iter (+ res 1))
        (- res 1)))
  (iter 1))

(define x (cons 4 6)) 
(car x) 
(cdr x) 

ex2.6

這題是關於Church計數,首先我們來看一下維基百科上的定義:

---------------------------------我-----------是--------分---------割----------線----------------------------------------------

0λf.λx. x
1λf.λx. f x
2λf.λx. f (f x)
3λf.λx. f (f (f x))
...
nλf.λx. fn x
...

就是說,自然數 n 被表示為 Church 數n,它對於任何 lambda-項 FX 有著性質:

n F X
=β Fn X

---------------------------------我-----------是--------分---------割----------線----------------------------------------------

按照我的理解是:0代表函式f在變數x上作用0次,1代表函式f在變數x上作用1次,... ... ,n代表函式f在變數x上作用n次;其中函式f和變數x是使用者自己定義的。上述等式左邊代表特殊的0~n(其實他們是函式,需要知道f, x才能求值,也就是需要傳入2個引數)

例如我們可以定義x=0,f(x)=x+1,那麼等式左邊的0~n求值後就對應自然數中的0~n

另外Church計數還定義瞭如下操作:

---------------------------------我-----------是--------分---------割----------線----------------------------------------------

加法函式 plus(m,n)=m+n 利用了恆等式f^{(m+n)}(x)=f^m(f^n(x))

plusλm.λn.λf.λx. m f (n f x)

後繼函式 succ(n)=n+1β-等價於 (plus 1)。

succλn.λf.λx. f (n f x)

乘法函式 times(m,n)=m*n 利用了恆等式f^{(m*n)} = (f^m)^n

multλm.λn.λf. n (m f)

指數函式 exp(m,n)=m^n 由 Church 數定義直接給出。

expλm.λn. n m
---------------------------------我-----------是--------分---------割----------線----------------------------------------------

有了上面這些知識,這題就比較容易理解了。這題給出了0後繼函式succ的定義,讓我們求1,2, plus的定義。

已知0後繼函式succ的定義:

(define zero (lambda (f) (lambda (x) x)))
(define (add-1 n)  ;; 
  (lambda (f) (lambda (x) (f ((n f) x)))))
從上面的定義上我們可以看出:zero是一個函式(包含一個引數),它返回一個identity函式(即本身);也就是說函式f在變數x上作用了0次,即直接返回x的值。

例如我們可以進行如下的呼叫((zero f) 100),其中f可以為任意函式,那麼這個表示式的值為100

根據上面的2個定義,我們可以進行如下推到:

  one
= add-1 zero
= lambda (f) (lambda (x) (f ((zero f) x)))
= lambda (f) (lambda (x) (f ((lambda (x) x) x)))
= lambda (f) (lambda (x) (f x))

因而one定義如下:

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

因而two定義如下:

(define two (lambda (f) (lambda (x) (f (f x)))))

從而我們可以推出n的定義:

(define n (lambda (f) (lambda (x) (f (f ... f (x))))))
上面的f呼叫了n次,當然這個寫法不規範,但是我們可以這樣認為。

我們在使用n這個函式的時候可以這樣呼叫:((n f) x),其中f, x可以由使用者定義,它的值就是f(...f(x)...)

下面我們來解決加法問題。

(add m n)可以認為對變數n呼叫了m次add-1函式

呼叫1次add-1:

(lambda (f) (lambda (x) (f ((n f) x))))

(lambda (f) (lambda (x) ((one f) ((n f) x))))

呼叫2次add-1:

(lambda (f) (lambda (x) (f (f((n f) x)))))
(lambda (f) (lambda (x) ((two f) ((n f) x))))
....

....

呼叫m次add-1:

(lambda (f) (lambda (x) (f...((n f) x))))
也就是:
(lambda (f) (lambda (x) ((m f) ((n f) x))))
因而有如下定義:
(define (add m n)
  (lambda (f) (lambda (x) ((m f) ((n f) x)))))