- 论坛徽章:
- 0
|
我在看 SICP 时碰到的一个问题,开始有点迷惑(现在好像又明白了)。抛块砖头,说一下自己的看法。
相关资料:
普通约束器件的 process-forget-value 函数最后会调用 process-new-value,中文版的 p202 页第 4 行说道:
如果加法对象被告知自己的一个连接器丧失了值,那么它就会要求其所有连接器丢掉它们的值(实际上,只有那些被该加法对象设置值的连接器会丢掉值),而后在运行它的过程 process-new-value。需要最后这一步的原因是,还可能有些连接器仍然有自己的值(也就是说,某个连接器过去所拥有的值原来就不是由这个加法对象设置的),这些值又可能需要通过这一加法对象传播。
加法器的代码如下
- (define (adder a1 a2 sum)
- (define (process-new-value)
- (cond ((and (has-value? a1) (has-value? a2))
- (set-value! sum
- (+ (get-value a1) (get-value a2))
- me))
- ((and (has-value? a1) (has-value? sum))
- (set-value! a2
- (- (get-value sum) (get-value a1))
- me))
- ((and (has-value? a2) (has-value? sum))
- (set-value! a1
- (- (get-value sum) (get-value a2))
- me))))
- (define (process-forget-value) ;; <-- here
- (forget-value! sum me)
- (forget-value! a1 me)
- (forget-value! a2 me)
- (process-new-value)) ;; <-- here
- (define (me request)
- (cond ((eq? request 'I-have-a-value)
- (process-new-value))
- ((eq? request 'I-lost-my-value)
- (process-forget-value))
- (else
- (error "Unknown request -- ADDER" request))))
- (connect a1 me)
- (connect a2 me)
- (connect sum me)
- me)
复制代码
英文版对应的文字:
If the adder is told that one of its connectors has lost a value, it requests that all of its connectors now lose their values. (Only those values that were set by this adder are actually lost.) Then it runs process-new-value. The reason for this last step is that one or more connectors may still have a value (that is, a connector may have had a value that was not originally set by the adder), and these values may need to be propagated back through the adder.
一开始,我觉得加法器在 process-forget-value 中不需要调用 process-new-value.
看一下这个 adder,a+b=c。每个连接器既是输入,也是输出。如果其中有两个确定了,则第三个就确定下来了。比如:
- 用户(或器件) A 设置 a=1, b=2 则 c 被 adder 设置为 3,此时我们可以:
- forget 掉 a 的值,则 a 会通知 adder 忘掉它的值,从而 c 的值被清除,因为它的值是 adder 设置;但 b 的值被保留,因为不是 adder 设置的。
这时调用 proce-new-value 没有意义,因为三个信号中有两个被清除了。
- forget 掉 b 的值与 forget 掉 a 的值类似。
- forget 掉 c 的值,这个是非法的。首先,c 的 informant,也就 adder 中的 me,是个内部标志,我们在外边是看不到的。如果耍些小手段,得到这个值,可以让 c forget。但 c 通知周边约束时,使用的是 for-each-except。也就是说,它不会去通知它的 informant,即 adder。结果变成 a=1, b=2, c 没有值。这是个错误状态。
那么 proce-new-value 不是正好可以解决这个问题吗?可是此时 adder 根本不知道 c 的值已经没有了,因为 c 没哟通知它。
- A 把 a 设置为 1, B 把 b 设置为 2,adder 把 c 设置为 3.
此时情况与上面类似。
基于上面的分析,我觉得在 process-no-value 中调用 process-new-value 是多余的。
但后来仔细想了一下,有下面这种罕见的情况:加法器的初始情形为: A 设置 a=1, B 设置 b=2, C 设置 c=3。这是可以做到的,代码如下:
- (set-value! a 1 'A)
- (set-value! b 2 'A)
- (set-value! c 3 'C)
- (adder a b c)
- (probe 'a a)
- (probe 'b b)
- (probe 'c c)
复制代码
交换演示:
- > (load "test.scm")
- Probe: a = 1
- Probe: b = 2
- Probe: c = 3
- > (forget-value! a 'A)
- Probe: a = ?
- Probe: a = 1done
复制代码
a 值被重新计算了出来。这种情形应该不多,一开始的稳定状态不是由约束系统本身计算出来的,而且强行设置的。
这种情形是我在写这个帖子的过程中想到的,之前想到的另一些情况见下贴。
[ 本帖最后由 win_hate 于 2009-1-3 12:50 编辑 ] |
|