这次回顾第三章第四部分习题。

学习资料:

https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/index.htm

https://github.com/DeathKing/Learning-SICP

https://mitpress.mit.edu/sites/default/files/sicp/index.html

https://www.bilibili.com/video/BV1Xx41117tr?from=search&seid=14983483066585274454

参考资料:

https://sicp.readthedocs.io/en/latest

http://community.schemewiki.org/?SICP-Solutions

http://community.schemewiki.org/?sicp

3.33(p205)

(define (averager a b c)
    (let ((d (make-connector))
          (e (make-connector)))
         (adder a b d)
         (constant 2 e)
         (multiplier d e c)))

3.34(p205)

参考资料:

https://sicp.readthedocs.io/en/latest/chp3/34.html

代码

(load "constraints.scm")

(define (squarer a b)
    (multiplier a a b))

(define a (make-connector))
(define b (make-connector))
(squarer a b)
(probe "a" a)
(probe "b" b)

(set-value! a 1 'user)
(newline)
(forget-value! a 'user)
(newline)
(set-value! b 2 'user)
(newline)

(exit)

实验结果:

Probe: a = 1
Probe: b = 1

Probe: a = ?
Probe: b = ?

Probe: b = 2

没有给$a$赋值的原因是,process-new-value无法给$m_1,m_2$都没值的情形赋值(注意到对于平方的情形,这种情况是可以赋值的):

(define (multiplier m1 m2 product)
  (define (process-new-value)
    (cond ((or (and (has-value? m1) (= (get-value m1) 0))
               (and (has-value? m2) (= (get-value m2) 0)))
           (set-value! product 0 me))
          ((and (has-value? m1) (has-value? m2))
           (set-value! product
                       (* (get-value m1) (get-value m2))
                       me))
          ((and (has-value? product) (has-value? m1))
           (set-value! m2
                       (/ (get-value product) (get-value m1))
                       me))
          ((and (has-value? product) (has-value? m2))
           (set-value! m1
                       (/ (get-value product) (get-value m2))
                       me))))
  (define (process-forget-value)
    (forget-value! product me)
    (forget-value! m1 me)
    (forget-value! m2 me)
    (process-new-value))
  (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 -- MULTIPLIER" request))))
  (connect m1 me)
  (connect m2 me)
  (connect product me)
  me)

3.35(p205)

参考资料:

https://sicp.readthedocs.io/en/latest/chp3/35.html

对之前的问题进行修改:

(load "constraints.scm")

(define (square a)
    (* a a))

(define (squarer a b)
    (define (process-new-value)
        (cond ((and (has-value? b) (< (get-value b) 0)) 
                (error "square less than 0 -- SQUARER" (get-value b)))
              ((and (has-value? b) (>= (get-value b) 0))
                (set-value! a (sqrt (get-value b)) me))
              ((has-value? a)
                (set-value! b (square (get-value a)) me))))
    (define (process-forget-value) 
        (forget-value! a me)
        (forget-value! b me)
        (process-new-value))
    (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 -- SQUARER" request))))
    (connect a me)
    (connect b me)
    me)

(define a (make-connector))
(define b (make-connector))
(squarer a b)

(probe "a" a)
(newline)
(probe "b" b)
(newline)
(set-value! a 1 'user)
(newline)
(forget-value! a 'user)
(newline)
(set-value! b 2 'user)

(exit)

结果如下:

Probe: a = 1
Probe: b = 1

Probe: a = ?
Probe: b = ?

Probe: b = 2
Probe: a = 1.4142135623730951

3.36(p205)

参考资料:

https://sicp.readthedocs.io/en/latest/chp3/36.html

3.37(p205)

(load "constraints.scm")

(define (c+ x y)
    (let ((z (make-connector)))
        (adder x y z)
        z))

(define (c* x y)
    (let ((z (make-connector)))
        (multiplier x y z)
        z))

(define (c/ x y)
    (let ((z (make-connector)))
        (multiplier y z x)
        z))

(define (cv v)
    (let ((z (make-connector)))
        (constant v z)
        z))

; test
(define (celsius-fahrenheit-converter x)
    (c+ (c* (c/ (cv 9) (cv 5))
            x)
        (cv 32)))

(define C (make-connector))
(define F (celsius-fahrenheit-converter C))

(set-value! C 5 'user)
(newline)
(probe "C" C)
(probe "F" F)
(newline)

(exit)

结果如下:

Probe: C = 5
Probe: F = 41

3.38(p210)

(a)

三种操作一共有六种排列,因此可能的结果如下:

100 -> 110 -> 90 -> 45
100 -> 80 -> 90 -> 45
100 -> 110 -> 55 -> 35
100 -> 80 -> 40 -> 50
100 -> 50 -> 60 -> 40
100 -> 50 -> 30 -> 40
(b)

此时区别在于会出现并发的情况:

两个操作并发:

100 -> 110 -> 90 / 55
100 -> 80 -> 90 / 40
100 -> 50 -> 60 / 30

三个操作并发:

100 -> 110 / 80 /50

3.39(p212)

参考资料:

https://sicp.readthedocs.io/en/latest/chp3/39.html

下面两种计算过程是显然的:

10 -> (set! x ((s (lambda () (* x x))))) = 100 -> (set! x (+ x 1)) = 101

10 -> (set! x (+ x 1)) = 11 -> (set! x ((s (lambda () (* x x))))) = 121

最后一种计算过程为:

10 -> (set! x ((s (lambda () (* x x))))) = 100
   -> (set! x (+ x 1)) = 11

这种情形对应并发运行,所以最终的结果为$11$或$100$。

3.40(p212)

全部情形:

10 -> (set! x (* x x)) = 100 -> (set! x (* x x x)) = 1000000
10 -> (set! x (* x x x)) = 1000 -> (set! x (* x x)) = 1000000
10 -> (set! x (* x x)) = 100
   -> (set! x (* x x x)) = 1000
10 -> (set! x (* 10 100 100)) = 100000
   -> (set! x (* 10 10 100)) = 10000
10 -> (set! x (* 10 1000)) = 10000

如果改成串行化,那么结果可能为:

10 -> (set! x (* x x)) = 100 -> (set! x (* x x x)) = 1000000
10 -> (set! x (* x x x)) = 1000 -> (set! x (* x x)) = 1000000

3.41(p213)

参考资料:

http://community.schemewiki.org/?sicp-ex-3.41

不正确,因为balance操作不改变balance的值,所以不需要加入串行组。

3.42(p213)

参考资料:

https://sicp.readthedocs.io/en/latest/chp3/42.html

http://community.schemewiki.org/?sicp-ex-3.42

这样修改的疑问是,如果调用如下语句会发生什么

(parallel-execute
    ((account 'deposit) 10)
    ((account 'deposit) 10)
	)

即,两个protected-withdraw能否会并发运行,个人倾向于两者不能并发运行,因此这样修改是有问题的。