SICP勉強会(1)

SICP勉強会をした。やった範囲は3.1.1から3.2.1まで。

書いたコード

; 3.1.1 ---------------------------------------------------

(define balance 100)

(define (withdraw amount)
  (if (>= balance amount)
    (begin (set! balance (- balance amount))
           balance)
    "Insufficient funds"))

(define new-withdraw
  (let ((balance 100))
    (lambda (amount)
      (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))))

(define (make-withdraw balance)
  (lambda (amount)
    (if (>= balance amount)
      (begin (set! balance (- balance amount))
             balance)
      "Insufficient funds")))

(define (make-account balance)
  (define (withdraw amount)
    (if (>= balance amount)
      (begin (set! balance (- balance amount))
             balance)
      "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (dispatch m)
    (cond ((eq? m 'withdraw) withdraw)
          ((eq? m 'deposit) deposit)
          (else (error "Unknown request -- MAKE-ACCOUNT"
                       m))))
  dispatch)

; ex 3.1
(define (make-accumulator sum)
  (lambda (n)
    (set! sum (+ sum n))
    sum))

; ex 3.2
(define (make-monitored f)
  (let ((count 0))
    (lambda (x)
      (cond ((eq? x 'how-many-calls?) count)
            ((eq? x 'reset-count) (set! count 0))
            (else (set! count (+ count 1))
                  (f x))))))

; ex 3.3
(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
      (begin (set! balance (- balance amount))
             balance)
      "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (dispatch p m)
    (cond ((not (eq? p password)) (lambda (x) "Incorrect password"))
          ((eq? m 'withdraw) withdraw)
          ((eq? m 'deposit) deposit)
          (else (error "Unknown request -- MAKE-ACCOUNT"
                       m))))
  dispatch)

; ex 3.4
(define (call-the-cops) "CALL-THE-COPS!!")

(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
      (begin (set! balance (- balance amount))
             balance)
      "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (let ((fail-count 0))
    (define (dispatch p m)
      (cond ((not (eq? p password))
             (set! fail-count (+ fail-count 1))
             (if (>= fail-count 7)
               (lambda (x) (call-the-cops))
               (lambda (x) "Incorrect password")))
            ((eq? m 'withdraw)
             (set! fail-count 0)
             withdraw)
            ((eq? m 'deposit)
             (set! fail-count 0)
             deposit)
            (else (error "Unknown request -- MAKE-ACCOUNT"
                         m))))
    dispatch))

; 3.1.2 ---------------------------------------------------

(define (rand-update x)
  (modulo (+ (* x 1103515245) 12345) 2147483648))

(define random-init 56243)

(define rand
  (let ((x random-init))
    (lambda ()
        (set! x (rand-update x))
        x)))

(define (random x)
  (* x (/ (rand) 2147483648)))

(define (estimate-pi trials)
  (sqrt (/ 6 (monte-carlo trials cesaro-test))))

(define (cesaro-test)
  (= (gcd (rand) (rand)) 1))

(define (monte-carlo trials experiment)
  (define (iter trials-remaining trials-passed)
    (cond ((= trials-remaining 0) (/ trials-passed trials))
          ((experiment) (iter (- trials-remaining 1)
                              (+ trials-passed 1)))
          (else (iter (- trials-remaining 1) trials-passed))))
  (iter trials 0))

; ex 3.5
(define (unit-circle x y)
  (< (+ (* x x) (* y y)) 1.0))

(define (random-in-range low high)
  (let ((range (- high low)))
    (+ low (random range))))

(define (estimate-integral pred x1 y1 x2 y2 trials)
  (monte-carlo trials
               (lambda () (pred (random-in-range x1 x2)
                                (random-in-range y1 y2)))))

(define (estimate-pi trials)
  (* 4.0 (estimate-integral unit-circle 0 0 1.0 1.0 trials)))

; ex 3.6
(define rand2
  (let ((x random-init))
    (lambda (operate)
      (cond ((eq? operate 'generate)
              (set! x (rand-update x))
              x)
            ((eq? operate 'reset)
              (lambda (new-value) (set! x new-value)))
            (else (error "Invalid operation -- RAND2"))))))

; 3.1.3 ---------------------------------------------------

; ex 3.7
(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
      (begin (set! balance (- balance amount))
             balance)
      "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (dispatch p m)
    (cond ((eq? m 'correct-password?) (eq? p password))
          ((not (eq? p password)) (lambda (x) "Incorrect password"))
          ((eq? m 'withdraw) withdraw)
          ((eq? m 'deposit) deposit)
          (else (error "Unknown request -- MAKE-ACCOUNT"
                       m))))
  dispatch)

(define (make-joint acc password new-password)
  (define (dispatch p m)
    (cond ((eq? m 'correct-password) (eq? p new-password))
          ((not (eq? p new-password)) (lambda (x) "Incorrect password"))
          ((eq? m 'withdraw) (acc password 'withdraw))
          ((eq? m 'deposit) (acc password 'deposit))
          (else (error "Unknown request -- MAKE-JOINT"
                       m))))
  (if (acc password 'correct-password?)
      dispatch
      "Incorrect password"))

; ex 3.8
(define f
  (let ((y 0))
    (lambda (x)
      (if (= y 0)
          (begin (set! y 1)
                 x)
          0))))