本人做的SICP習題第3章,如有錯誤請指正,用的解釋器是Racket
練習3.1
;; 累加器
(define (make-accumulator initial)
(lambda (x)
(let ((sum (+ initial x)))
(set! initial (+ initial x))
sum)))
練習3.2
;; 監控器
(define (make-monitored f)
(let ((cnt 0))
(define (dispatch op)
(cond ((equal? op "how-many-calls") cnt)
((equal? op "reset-count") (set! cnt 0))
(else
(begin
(set! cnt (+ cnt 1))
(f op)))))
dispatch))
練習3.3
;; 賬戶
(define (make-account balance password)
;; 判斷密碼是否正確
(define (password-correct? pass)
(equal? pass password))
(define (withdraw pass amount)
(if (password-correct? pass)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds")
"Incorrect password"))
(define (deposit pass amount)
(if (password-correct? pass)
(begin (set! balance (+ balance amount))
balance)
"Incorrect password"))
(define (dispatch m)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request -- MAKE-ACCOUNT"
m))))
dispatch)
練習3.4
;; 賬戶
(define (make-account balance password)
(let ((cnt 0))
;; 判斷密碼是否正確
(define (password-correct? pass)
(if (equal? pass password)
true
(begin
(set! cnt (+ cnt 1))
(if (> cnt 6)
(call-the-cops)
false)
false)))
;; 叫警察
(define (call-the-cops)
(display "Call the cops\n"))
(define (withdraw pass amount)
(if (password-correct? pass)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds")
"Incorrect password"))
(define (deposit pass amount)
(if (password-correct? pass)
(begin (set! balance (+ balance amount))
balance)
"Incorrect password"))
(define (dispatch m)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request -- MAKE-ACCOUNT"
m))))
dispatch))
練習3.5
先寫生成指定範圍隨機數的代碼,racket和scheme略有不同
;; 生成隨機數
#lang racket
(provide (all-defined-out) )
;; 生成指定範圍的隨機數
(define (random-in-range low high)
(let ((ranges (- high low)))
(+ low (* (random) ranges))))
蒙特卡洛測試代碼,順便寫一個小測試
;; Exercise 3.5
;; 蒙特卡羅法計算積分
#lang racket
(require "random-in-range.rkt")
;; 計算積分
(define (estimate-integral x1 x2 y1 y2 P)
;; 蒙特卡洛測試
(define (monte-carlo trials)
(define (iter trials-remains cnt)
(cond ((= trials-remains 0) cnt)
((P (random-in-range x1 x2) (random-in-range y1 y2))
(iter (- trials-remains 1) (+ cnt 1)))
(else (iter (- trials-remains 1) cnt))))
(/ (iter trials 0) trials))
(* 1.0 (* (* (- x2 x1) (- y2 y1)) (monte-carlo 100000))))
;; 測試
;; 判斷點是否落在f=x^2曲線下方
(define (test x y)
(<= y (* x x)))
(estimate-integral 2 3 0 20 test)
練習3.6
我的racket沒有rand-update,所以用一個遞增的東西模擬一下
;; Exercise 3.6
;; 可以重置的rand生成
#lang racket
;; 帶重置隨機數生成
(define (rand-with-reset random-init)
(let ((x random-init))
(define (generate)
(set! x (rand-update x))
x)
(define (reset new-value)
(set! x new-value))
(define (dispatch op)
(cond ((equal? op 'generate) generate)
((equal? op 'reset) reset)
(else ("Wrong Operation"))))
dispatch))
;; 模擬rand-update
(define (rand-update x)
(+ x 1))
(define generator (rand-with-reset 0))
((generator 'generate))
((generator 'generate))
((generator 'reset) 7)
((generator 'generate))
((generator 'generate))
測試一下
練習3.7
先改一下之前的account代碼,原來把校驗密碼放在了每個函數裏,現在放在dispatch
;; 賬戶
(define (make-account balance password)
(let ((cnt 0))
;; 判斷密碼是否正確
(define (password-correct? pass)
(if (equal? pass password)
true
(begin
(set! cnt (+ cnt 1))
(if (> cnt 6)
(call-the-cops)
false)
false)))
;; 叫警察
(define (call-the-cops)
(display "Call the cops\n"))
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
"Insufficient funds"))
(define (deposit amount)
(begin (set! balance (+ balance amount))
balance))
(define (dispatch m pass)
(if (password-correct? pass)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request -- MAKE-ACCOUNT"
m)))
("Incorrect password")))
dispatch))
make-joint就很簡單了
;; 連接賬戶
(define (make-joint acc password joint-password)
(define (dispatch op pass)
(if (equal? pass joint-password)
(acc op password)
(error "Incorrect password")))
dispatch)
練習3.8
;; 測試
(define f
(lambda (first)
(set! f (lambda (second) 0))
first))