SICP 読み (96) 3.1.1 局所状態変数

一旦停止後、再発信。2 章のラスト問題は微妙なまま次に進む事に。

問題 3.1

とりあえず例示されている実行例を元に試験を書いてみた。

#!/usr/bin/env gosh

(use math.const)
(use test.unit)
(require "3.1")

(define-test-suite "3.1"
 ("sample"
  ("sample"
   (let ((A (make-accumulator 5)))
     (assert-equal 15 (A 10))
     (assert-equal 25 (A 10)))
   )
  )
)

とりあえず、この例から理解できるのは

  • make-accumulator 手続きで局所状態変数が 5 に設定された
  • 次の手続き (A 10) で局所状態変数に 10 が加えられた (値は 15)
  • その次の手続き (A 10) で局所状態変数に 10 が加えられた (値は 25)

という事になる。

直前にある銀行残高の例をパクるとこんなカンジ??

(define (make-accumulator n)
 (lambda (m)
   (begin (set! n (+ n m))
          n)))

試験パス。なんか 2 章の最後らへんの重さが嘘のようなナニだな。

問題 3.2

これは又オモロげな問題だなぁ。これも例示されているソレでまず試験を書いておく。

#!/usr/bin/env gosh

(use math.const)
(use test.unit)
(require "3.2")

(define-test-suite "3.2"
 ("sample"
  ("sample"
   (let ((s (make-monitored sqrt)))
     (assert-equal 10.0 (s 100))
     (assert-equal 1 (s 'how-many-calls?)))
   )
  )
)

これは p.130 のような dispatch 手続きが必要だな。でもカウンタをどう実装すれば良いのかな?? dispatch を返す時に初期化なの?

(begin (set! c 0)
      dispatch)

みたいな感じ??

とりあえず作ってみる。適当にヒネリ出したのが以下。

(define (make-monitored p)
 (define (how-many-calls?) c)
 (define (reset-count)
   (set! c 0)
   'cleared)
 (define (dispatch m)
   (cond ((eq? m 'howmany-calls) how-many-calls?)
         ((eq? m 'reset-count) reset-count)
         (else p m)))
 (begin (set! c 0)
        dispatch))

で試験してみると

*** ERROR: symbol not defined: #<identifier user#c>

と叱られる。set! するのは定義済みでないと駄目なのか。p.129 な例では let 使ってますな。この方式で実装してみると以下か。ちなみに上の方法では手続きが戻るので例示されている方法というか上の試験には通らない (手続きが戻る)。

(define (make-monitored p)
 (let ((c 0))
   (lambda (m)
     (cond ((eq? m 'how-many-calls?) c)
           ((eq? m 'reset-count)
            (set! c 0)
            'cleared)
           (else
            (begin (set! c (+ c 1))
                   (p m)))))))

これで一応最初の試験は通りましたが、試験してない手続き等あり。

追記

ぢつはこれ、金曜に入れるハズだったソレだったりする。