SICP 読み (121) 3.3.5 制約の拡散

connector 周りの試験と connector 未定義を前提とした各制約の試験について検討してみる事に。
とりあえず connector の試験を検討してみる。とりあえずオブジェクト生成直後の時点では、

  • value は false
  • informant も false
  • constraints は空

という状態なはずなんでこれを確認。
ってか、constraints は可視ではないので確認は略。

  ("connector"
   ("shortly after make-connector"
    (let ((a (make-connector)))
      (assert-false (a 'has-value?))
      (assert-false (a 'value))
      )
    )
   )

あるいはメセジの応答確認してみるか。

   ("response of send message"
    (let ((a (make-connector)))
      (assert-not-null (a 'set-value!))
      (assert-not-null (a 'forget))
      (assert-not-null (a 'connect))
      (assert-error (lambda () (a 'x)))
      )
    )

次は set-value! してみるか

   ("set-value!"
    (let ((a (make-connector)))
      (assert-equal 'done ((a 'set-value!) 2 'user))
      (assert-equal 2 (a 'value))
      (assert-true (a 'has-value?))
      (assert-error (lambda () ((a 'set-value!) 3 'user)))
      (assert-equal 'ignored ((a 'set-value!) 2 'user))
      )
    )

で、ここまで書いて気が付いたんですが、昨晩書いたソレに強烈なボケが混入している模様。

制約同士がコネクタで繋っているケイスもある訳で (例示されているソレもそのパターンになっております)、逆に言えば関わりの無い制約に勝手に値を変更されては困りますな。

http://d.hatena.ne.jp/yamanetoshi/20070724/1185280594

とほほ、ダウトだし。set-value! に setter を渡さなければならない理由は、コネクタには複数の制約が関連づけられていて、ある一方の制約によって値が変更された場合、もう一方 (あるいはそれ以外??) の制約にのみ値が変わった影響が及ぼさなければならないから、と言えば良いのだろうか。
コネクタ単体で何かをする場合には setter はとりあえず何でも構わないようです。と思ったら一旦 set した値を forget させるためには同一の setter でなければ NG な模様。きちんと読まずにたれ流してるのがバレバレだなぁ (とほほ

   ("reset"
    (let ((a (make-connector)))
      (assert-equal 'done ((a 'set-value!) 2 'user))
      (assert-equal 'ignored ((a 'forget) 'xxx))
      (assert-equal 'done ((a 'forget) 'user))
      (assert-equal 'done ((a 'set-value!) 3 'xxx))
      )
    )

で、一旦 forget したら次に set-value! する時の setter は変わっても構わない、と。しかしここまで色々やってるんですが、未だに理解が微妙。
やっぱダミーの制約作って何らかの試験をしないと駄目かも。

ダミーの制約

例えば端子を二つ持ってて片方から来た値をそのまま片方に伝えるだけ、な制約をダミーでこしらえて試験してみれば良いのかな。

   ("dummy constraint"
    (let ((a (make-connector))
	  (b (make-connector))
	  (c (make-connector)))
      (define (dmy a1 a2)
	(define (new-value)
	  (cond ((has-value? a1) (set-value! a2 (get-value a1) me))
		((has-value? a2) (set-value! a1 (get-value a2) me))))
	(define (forget-value)
	  (forget-value! a1 me)
	  (forget-value! a2 me)
	  (new-value))
	(define (me request)
	  (cond ((eq? request 'I-have-a-value)
		 (new-value))
		((eq? request 'I-lost-my-value)
		 (forget-value))
		(else
		 (error "Unknown request -- ADDER" request))))
	(connect a1 me)
	(connect a2 me)
	me)
      (dmy a b)
      (dmy a c)
      (assert-false (has-value? a))
      (assert-false (has-value? b))
      (assert-false (has-value? c))

      (set-value! b 1 'test)
      (assert-true (has-value? a))
      (assert-true (has-value? b))
      (assert-true (has-value? c))
      (assert-equal 1 (get-value a))
      (assert-equal 1 (get-value c))

      (forget-value! b 'test)
      (assert-false (has-value? a))
      (assert-false (has-value? b))
      (assert-false (has-value? c))
      (assert-equal 1 (get-value c))

      (set-value! c 5 'user)
      (assert-true (has-value? a))
      (assert-true (has-value? b))
      (assert-true (has-value? c))
      (assert-equal 5 (get-value b))
      (assert-equal 5 (get-value a))
      )
    )
   )

connector 未定義なソレは別途。又、微妙に中途半端ですので別途追記を予定。