Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
72 lines (51 sloc) 3.22 KB

这个题困扰了我好几天,要想解决这个题目,我是按照题目说明,以half-adder为例子,来分析如果在add-action!中不立即调用(proc)时会发生什么。

这题网上的说法一般是:

如果没有立即执行(proc),那么agenda里面就没有待处理过程了。

其实这是**不准确的**,因为在改变一个电线的信号时,如果和其之前的信号不一样,会触发该电线上所有的`action-procedures`,那么这时也会调用`after-delay`过程,也即向`agenda`中添加待处理过程了。

其实,在add-action!中立即执行(proc),主要的目的是:

可以在电线信号不改变时,也调用after-delay过程,向agenda中添加待处理过程。

2016/08/21 更新

koallen指出,我之前分析的有些问题,现重新总结如下:

在一条电线连接到某电路上时,将输入端的action加入到agenda中,从而保证后面执行agenda中的action时,确保output端得到初始化。

下面来具体分析half-adderadd-action!立即执行(proc)agenda的变化,来佐证上面这个总结。

(load "lib/queue.scm")
(load "lib/simulator.scm")
; 测试时,需要把 add-action! 中的 (proc) 调用注释掉 😊
(define a (make-wire))
(define b (make-wire))
(define s (make-wire))
(define c (make-wire))
(define (half-adder a b s c)
  (let ((d (make-wire))
        (e (make-wire)))
    (or-gate a b d)
    (and-gate a b c)
    (inverter c e)
    (and-gate d e s)
    "ok"))
(half-adder a b s c)
; (display the-agenda) (newline)
(set-signal! a 1)
; (display the-agenda) (newline)
(propagate)
; (display (s 'get-signal))

上面是完整的测试程序,下面来分析执行最后三个过程时,agenda的变化:

  1. (half-adder a b s c)

调用 half-adder,将各个电线连接起来,这时 agenda 为空 2. (set-signal! a 1)

现在将 a 的信号置为1,这时下面两个过程将会被添加到 agenda 中

  1. (set-signal! d (logical-or 1 0)) logical-or of a and b
  2. (set-signal! c (logical-and 1 0)) logical-and of a and b
  3. (propagate)

开始启动仿真器,这时会去执行 agenda 中的仅有的两个过程(在步骤2中添加的)。 (set-signal! d (logical-or 1 0))执行后,由于改变了 d 的值,所以会把(set-signal! s (logical-and 1 0))添加到 agenda 中。

这里需要注意的是,(logical-and 1 0)的第二个参数之所以为0,是因为(set-signal! c (logical-and 1 0))执行后,由于电线 c 的信号从没改变过,所以(invert-input 0)过程不会被添加到 agenda 中,所以电线 e 的信号将一直保持为 0,所以 s 的最终值为 0。

  1. 而实际上,s 的最终值应该是 1 才对,如果在add-action!中立即执行(proc),那么在第一步(half-adder a b s c)时就会把各个门电路的 输入端的action加入到agenda中,这时电线 e 的值将会变为 1,也就避免上面步骤3所出现的问题了。

通过上面的分析,基本上能够理解为什么要在add-action!中立即执行(proc)了。

参考链接: