免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3831 | 回复: 2
打印 上一主题 下一主题

SICP 讨论:约束传播器的一个问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-01-03 11:49 |只看该作者 |倒序浏览
我在看 SICP 时碰到的一个问题,开始有点迷惑(现在好像又明白了)。抛块砖头,说一下自己的看法。

相关资料:



普通约束器件的 process-forget-value 函数最后会调用 process-new-value,中文版的 p202 页第 4 行说道:

如果加法对象被告知自己的一个连接器丧失了值,那么它就会要求其所有连接器丢掉它们的值(实际上,只有那些被该加法对象设置值的连接器会丢掉值),而后在运行它的过程 process-new-value。需要最后这一步的原因是,还可能有些连接器仍然有自己的值(也就是说,某个连接器过去所拥有的值原来就不是由这个加法对象设置的),这些值又可能需要通过这一加法对象传播。


加法器的代码如下


  1. (define (adder a1 a2 sum)
  2.   (define (process-new-value)
  3.     (cond ((and (has-value? a1) (has-value? a2))
  4.            (set-value! sum
  5.                        (+ (get-value a1) (get-value a2))
  6.                        me))
  7.           ((and (has-value? a1) (has-value? sum))
  8.            (set-value! a2
  9.                        (- (get-value sum) (get-value a1))
  10.                        me))
  11.           ((and (has-value? a2) (has-value? sum))
  12.            (set-value! a1
  13.                        (- (get-value sum) (get-value a2))
  14.                        me))))
  15.   (define (process-forget-value)                            ;; <-- here
  16.     (forget-value! sum me)
  17.     (forget-value! a1 me)
  18.     (forget-value! a2 me)
  19.     (process-new-value))                                      ;; <-- here
  20.   (define (me request)
  21.     (cond ((eq? request 'I-have-a-value)  
  22.            (process-new-value))
  23.           ((eq? request 'I-lost-my-value)
  24.            (process-forget-value))
  25.           (else
  26.            (error "Unknown request -- ADDER" request))))
  27.   (connect a1 me)
  28.   (connect a2 me)
  29.   (connect sum me)
  30.   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。这是可以做到的,代码如下:


  1. (set-value! a 1 'A)
  2. (set-value! b 2 'A)
  3. (set-value! c 3 'C)

  4. (adder a b c)
  5. (probe 'a a)
  6. (probe 'b b)
  7. (probe 'c c)
复制代码


交换演示:


  1. > (load "test.scm")

  2. Probe: a = 1
  3. Probe: b = 2
  4. Probe: c = 3

  5. > (forget-value! a 'A)

  6. Probe: a = ?
  7. Probe: a = 1done
复制代码


a 值被重新计算了出来。这种情形应该不多,一开始的稳定状态不是由约束系统本身计算出来的,而且强行设置的。

这种情形是我在写这个帖子的过程中想到的,之前想到的另一些情况见下贴。

[ 本帖最后由 win_hate 于 2009-1-3 12:50 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2009-01-03 12:27 |只看该作者

乘法器

与加法器不同,在乘法器的 process-forget-value 中调用 process-new-value 看上去是就是合理的。差别在于,加法器的约束很紧,而乘法器在某种情形下,要松一些。

设有乘法器



当 a 为 0 时,即使 b 没有值,乘法器也会把 c 设置为 0.


  1. (set-value! a 0 'A)
  2. (set-value! b 1 'B)


  3. (multiplier a b c)
  4. (probe 'a a)
  5. (probe 'b b)
  6. (probe 'c c)
复制代码


  1. > (load "test.scm")

  2. Probe: a = 0
  3. Probe: b = 1
  4. Probe: c = 0

  5. > (forget-value! b 'B)

  6. Probe: b = ?
  7. Probe: c = ?
  8. Probe: c = 0done
复制代码


在这里,尽管 b 值被清除导致  c 值被清除,但 c 值又马上被重新计算出来了。

在乘法器的启发下,不难构造出下面的器件:



其中 d 既可以通过 a,b, c 中的三个值求出,也可以通过两个值求出,甚至可以通过其中一个值求出。一个简单的方法就是让 d 为 a,b,c 的部分和。此时在 process-no-value 中调用  process-new-value 是必须的。

[ 本帖最后由 win_hate 于 2009-1-3 12:44 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2009-01-03 12:46 |只看该作者

再来一个例子

这个器件的 process-no-value 也是明显需要调用 process-new-value 的。

core.png (2.65 KB, 下载次数: 53)

core.png
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP