ディジタル回路のシミュレータ(問題3-28〜32)

ここ最近、体調を崩していたため、勉強日記の更新が滞ってしまいましたが、少しずつリカバリーしていきたいと思います。
「3.3.4 ディジタル回路のシミュレータ」の節は、読み物として非常に面白く、問題量としては多くないものの、サンプルコードを読み解くのに結構時間がかかってしまいました。「遅延」が絡んでくると、考慮しなければならないことが増えて大変だということを痛感しました。
問題3-28では、or-gateを実装します。

(define (logical-or a1 a2)
  (if (or (= a1 1) (= a2 1))
      1 0))

(define (or-gate a1 a2 output)
  (define (or-action-procedure)
    (let ((new-value
           (logical-or (get-signal a1) (get-signal a2))))
      (after-delay or-gate-delay
                   (lambda ()
                     (set-signal! output new-value)))))
  (add-action! a1 or-action-procedure)
  (add-action! a2 or-action-procedure)
  'ok)

問題3-29は、and-gateとinverterを組み合わせてor-gateを実装します。3・inverter-delay + 1・and-gate-delayの遅延が生じます。

(define (or-gate a1 a2 output)
  (let ((a2 (make-wire))
        (b2 (make-wire))
        (c (make-wire)))
    (inverter a1 a2)
    (inverter b1 b2)
    (and-gate a2 b2 c)
    (inverter c output)))

問題3-30は、全加算器を設計する問題です。コード自体は書いていませんが、前後のcarry-inとcarry-outをつなげてやることで実現することができそうです。half-adderでは、1・or-gate-delay + 2・and-gate-delay + 1・inverter-delayが生じ、一つのfull-adderでは、3・or-gate-delay + 4・and-gate-delay + 2・inverter-delayが生じるので、nビットの繰り上がり伝播加算器は、このfull-adderの遅延にnを乗じた遅れが生じることになると考えられます。
問題3-31と32については、agendaの仕組みを何度も目視し、処理をトレースし、紙の上で図示化しながら、なんとなく理解できたかなというレベルです。
問題3-31。wireにアクションを追加した時に、そのアクションを一回実行することによって、agendaのアクションスロットに追加されます。これをやらないと、直接set-signal!できないようなwireの初期化がなされないので、例えば、半加算器の真ん中に位置しているインバータの出入力wireが共に0となってしまい、半加算器全体として正しく動きません。
問題3-32。初期化アクション、実行時に追加されたアクションが、次々と時間区分キューに追加され、遅延が生じる場合は、新しい時間区分が生成されそのキューに遅延後のアクションが追加されていきます。キューではなく、先入先出法にしてしまうと、遅延アクションを設定した後に、昔のアクションが実行されてwireの値が変わってしまうという不都合が生じてしまいます。
このディジタル回路は難しいトピックでしたが、いろいろと考えされされる面白い内容だったと感じています。