《SICP》習題第3章(施工中)

本人做的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))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章