関数型言語の勉強にSICPを読もう - (28) 3章 - 標準部品化力、オブジェクトおよび状態 (127-133ページ)

3章はいよいよ代入とかオブジェクトとかが登場します。
参照透明性という概念や、代入という概念の導入で何が変わるかとかそのあたりが書いてあるようです。

代入と局所状態

問題3.1

この程度ならスラスラ書けるようになった。

(define (make-accumulator start)
  (lambda (num)
    (set! start (+ start num))
    start))

(define A (make-accumulator 5))
(define B (make-accumulator 10))
(display (A 3))
(display (B 3))
(display (A 3))

問題3.2

(define (make-monitored f)
  (let ((counter 0))
    (define (dispatch m)
      (if (eq? m 'how-many-calls?) counter
          (func m)))
    (define (func arg)
      (set! counter (+ counter 1))
      (f arg))
    dispatch))

(define s (make-monitored sqrt))

(display (s 100))
(display (s 144))

(display (s 'how-many-calls?))

問題3.3

僕の口座もこれで守ろう(棒読み

(define (make-account balance password)
  (define (dispatch p m)
    (if (eq? p password)
        (if (eq? m 'withdraw) withdraw
            (error "unknown op"))
        (error "wrong password")))
  (define (withdraw amount)
      (if (>= balance amount)
          (begin (set! balance (- balance amount)) balance)
          "insufficient funds"))
  dispatch)

(define hige-account (make-account 1000000 'hige-pass))

(display ((hige-account 'hige-pass 'withdraw) 450000))

(display ((hige-account 'crack 'withdraw) 450000))

問題3.4

accountの呼び出しは手続きが返ってくることを期待しているのでエラーも手続きで返そうとか欲張ったら汚くなった。
でも楽しいっす。

(define (call-the-cops)
  (display "help!help"))

(define (make-account balance password)
  (let ((wrong-times 0))
    (define (dispatch p m)
      (define (error-func arg)
        (display "you can not ")
        (display m)
        (display " ")
        (display arg)
        (display "\n"))
      (if (eq? p password)
          (begin
            (set! wrong-times 0)
            (if (eq? m 'withdraw) withdraw
                error-func))
          (begin
            (set! wrong-times (+ 1 wrong-times))
            (if (>= wrong-times 7) (begin (call-the-cops) error-func)
                error-func))))
    (define (withdraw amount)
      (if (>= balance amount)
          (begin (set! balance (- balance amount)) balance)
          "insufficient funds"))
    dispatch))

(define hige-account (make-account 1000000 'hige-pass))

(display ((hige-account 'hige-pass 'withdraw) 450000))

((hige-account 'crack1 'withdraw) 450000)
((hige-account 'crack2 'withdraw) 450000)
((hige-account 'crack3 'withdraw) 450000)
((hige-account 'crack4 'withdraw) 450000)
((hige-account 'crack5 'withdraw) 450000)
((hige-account 'crack6 'withdraw) 450000)
((hige-account 'crack7 'withdraw) 450000)

問題3.5

モンテカルロ積分ですが、思ったよりもとてもシンプルな概念なのでぜひこの問題はチャレンジしてみると面白いと思います。
モンテカルロは並列化できるからうれしいよねと、N氏に教えてもらい納得。

(use srfi-27)

;; モンテカルロ積分
(define (estimate-integral p x1 y1 x2 y2 trials)
  (define (experiment)
    (let ((x (random-in-range x1 x2))
          (y (random-in-range y1 y2)))
      (p x y)))
  (let ((s  (* (- y2 y1) (- x2 x1))))
    (* s (monte-calro trials experiment))))

(define (random-in-range low high)
  (let ((range (- high low)))
    (if (<= 1 range)
        (random-real)
    (+ low (random-integer range)))))

(define (monte-calro 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))

(define (double a)
  (* a a))

;; えいっ
(define (unit-circle x y)
  (<= (+ (double (- x 0.5)) (double (- y 0.5))) 0.25))
(display (* (estimate-integral unit-circle 0 0 1 1 50000000) 4))

結果は

3.14176

でした。

問題3.6


※「SICPを読もう」の目次はこちら


計算機プログラムの構造と解釈
Gerald Jay Sussman Julie Sussman Harold Abelson 和田 英一
ピアソンエデュケーション (2000/02)
売り上げランキング: 56,404