昨晩 gdgd だったので
整理リトライ。# compile 待ち、と言いつつこっちヤッてるアレではなかったり
primitive function box
- いくつかの wire を引数に取る
- 基本的に一つ以上の入力と一つの出力
- 内部定義な手続きを持つ
- 引数な wire を評価して値を取得しておく
- after-delay 手続きを使って出力な wire に取得した値を set-signal! する thunk をナニ
- 入力な wire に対して内部定義な手続きを add-action! する
うーん、頭がコンガラがるなと思ったら二種類の thunk を弄くっているからなのかなぁ。ポイントとしては
- primitive function box な手続きを wire を引数に渡して呼び出すことで
- 入力な wire の action-procedures な属性にに内部定義な手続きオブジェクトが登録される
- 一回手続きを呼び出す
基本的な作りとして wire に登録される thunk は primitive function box の中で定義されている thunk な手続きオブジェクト。このヒト達は基本的に set-signal! されて値が以前と変わった時に呼び出されます。
登録後に一回手続きが呼び出されるのですが、これで何が起きるのかというと上に記述されてますな、「内部定義な手続きを持つ」という項のソレです。
うーん
sample simulation の項に記述されてる以下なソレを評価した時に何が起きるかを確認してみます。
(half-adder input-1 input-2 sum carry) ok
これは内部で以下を順に、という形。(d と e は内部定義な wire)
(or-gate input-1 input-2 d) (and-gate input-1 input-2 carry) (inverter carry e) (and-gate d e sum)
この手続きを評価することで
- input-1 は or-gate と and-gate の内部手続きなオブジェクトが登録
- input-2 も同様
- carry は probe と inverter の内部手続きなオブジェクトが登録
- sum は probe な手続きオブジェクトが登録
という事になりつつ次第書きに
- or-gate の set-signal! な thunk が登録
- 出力な wire は d で delay は 3
- and-gate の set-signal! な thunk が登録
- 出力な wire は carry で delay は 5
- inverter の set-signal! な thunk が登録
- 出力な wire は e で delay は 2
- and-gate の set-signal! な thunk が登録
- 出力な wire は sum で delay は 5
なソレが設定される、のかな、、、
違う
delay がまず違う。inverter が 2 で and が 3 で or が 5 でした。
で、最初の segments の状態が以下なカンジ
((2 . ((lambda () (set-signal! e 1)))) ;; inverter の add-action! のソレ (3 . ((lambda () (set-signal! carry 0)) ;; 最初の and の add-action! のソレ (lambda () (set-signal! sum 0)))) ;; 最後の and の add-action! のソレ (5 . ((lambda () (set-signal! d 0))))) ;; or の add-action! のソレ
全然正確ではないです。current-time は 0 なので delay がそのままのります。次に input-1 が 1 になった時点で以下になります。
((2 . ((lambda () (set-signal! e 1)))) ;; inverter の add-action! のソレ (3 . ((lambda () (set-signal! carry 0)) ;; 最初の and の add-action! のソレ (lambda () (set-signal! sum 0)) ;; 最後の and の add-action! のソレ (lambda () (set-signal! carry 0)))) ;; input-1 が 1 になった (5 . ((lambda () (set-signal! d 0)) ;; or の add-action! のソレ (lambda () (set-signal! d 1))))) ;; input-1 が 1 になった
ここで propagate されます。先頭から順に取り出されるのか。e が 1 になったので状態チェンジ。って事で (+ 2 3) な and の結果がナニ。
((3 . ((lambda () (set-signal! carry 0)) ;; 最初の and の add-action! のソレ (lambda () (set-signal! sum 0)) ;; 最後の and の add-action! のソレ (lambda () (set-signal! carry 0)))) ;; input-1 が 1 になった (5 . ((lambda () (set-signal! d 0)) ;; or の add-action! のソレ (lambda () (set-signal! d 1)) ;; input-1 が 1 になった (lambda () (set-signal! sum 0))))) ;; e が 1 になった
そのままめくっていって、次に状態に変更があるのが d に 1 がセットされて時点。ここで (+ 5 3) なナニが追加になる。
((5 . ((lambda () (set-signal! sum 0)))) ;; e が 1 になった (8 . ((lambda () (set-signal! sum 1))))) ;; d も 1 になった
で、sum が 1 になった時点で probe が実行されるという訳か。これに続いて input-2 が 1 になったらどうなるか、というと。
((11 . ((lambda () (set-signal! carry 1)))) ;; input-2 が 1 になった (13 . ((lambda () (set-signal! d 1))))) ;; input-2 が 1 になった
ええと carry が 1 に変わったのでこうなります。あと current-time が 11 の時点で probe が動きます。
((13 . ((lambda () (set-signal! d 1)) ;; input-2 が 1 になった (lambda () (set-signal! e 0))))) ;; carry が 1 になった
d が 1 になるのは何の副作用もないですが、e が 0 になるのは状態が変わるという事なので、以下になりますか。
((16 . ((lambda () (set-signal! sum 0))))) ;; e が 0 になった
sum の状態も変更されたので probe が動く。
Exercise 3.31
何故必要なのか、という事ですが記憶していた通り、wire の初期状態を設定する必要があるから、という事になりますな。e な wire は初期状態が 1 というのがカギ。