我在SICP的练习3.6上有困难。它们给出伪随机数生成器的下列代码:
(define rand
(let ((x random-init))
(lambda ()
(set! x (rand-update x))
x)))为测试目的,我添加了以下内容:
(define (rand-update x) (+ x 1))
(define random-init 4)重复应用产生
> (rand)
5
> (rand)
6
> (rand)
7正如我所希望的,虽然我不明白为什么会这样。无论如何,练习3.6要求我们修改rand,以便它接受一个参数,将其指示给'generate或'reset。
首先,我尝试设置一个具有生成条件的rand。然而,我无意中发现了第一个障碍。
(define (rand-new instruction)
(let ((x random-init))
(cond ((eq? instruction 'generate)
(lambda ()
(set! x (rand-update x))
x)))))给我
> ((rand-new 'generate))
5
> ((rand-new 'generate))
5
> ((rand-new 'generate))
5将let表达式移到分词中也是如此,如下所示:
(define (rand-new instruction)
(cond ((eq? instruction 'generate)
(let ((x random-init))
(lambda ()
(set! x (rand-update x))
x)))))那么,为什么第一个函数可以工作,而新函数却不能工作呢?是否与条件的使用有关?还是增加了一个参数?
更新(19/03/20)
阅读下一节关于计算环境模型的文章(第3.2节),我得到了理解正在发生的事情所必需的理论。我最后
(define (random-number-generator initial update)
(define (generate)
(begin (set! initial (update initial))
initial))
(define (reset new-value)
(begin (set! initial new-value)
initial))
(define (dispatch message)
(cond ((eq? message 'generate) (generate))
((eq? message 'reset) reset)
(else "Procedure not found!")))
dispatch)
(define rand (random-number-generator 5 rand-update))发布于 2020-03-15 13:13:59
理解第一个版本为什么工作(而另一个版本不工作)的关键在于前三行:
(define rand
(let ((x random-init))
(lambda ()正如您所看到的,名称rand被分配给lambda --但是在这样做之前,变量x是在lambda之外的作用域中创建的,这意味着:无论我们调用rand多少次,x中的值都会“记住”它的前一个值,我们在上一次调用中设置了这个值:(set! x (rand-update x))。
因此,您必须尊重这个let和那个lambda的位置,否则您创建的过程在调用之间不会有任何“内存”。此外,我认为这个练习并不是要求您创建自己的random过程,只需为接受所需消息的内置过程创建一个包装器就足够了:
(define (make-rand)
(λ (msg)
(case msg
('reset (λ (seed) (random-seed seed)))
('generate (random)))))
(define rand (make-rand))例如:
((rand 'reset) 42)
(rand 'generate)
=> 0.07337258110323383
(rand 'generate)
=> 0.0887121382290788
((rand 'reset) 42)
(rand 'generate)
=> 0.07337258110323383
(rand 'generate)
=> 0.0887121382290788如果您决定实现您自己版本的random,请尝试将这些过程保持独立(正如我前面所做的),如果您将所有内容放在一个地方,事情很快就会变得混乱。
发布于 2020-03-16 08:26:32
x不包含在我们的“随机”过程中。x包含在使我们的“随机”过程中。解决方案的形式如下:
(define (make-rand)
(define x 0)
...
<proc>)
(define my-rand (make-rand))
((my-rand 'reset) 42)
(my-rand 'generate)
(my-rand 'generate)因此,make-rand返回一个过程<proc>,该过程:
给定消息的
'generate返回下一个随机数。'reset返回另一个过程,该过程接受一个新值并将其赋值给x.。
使用定义(命名过程) make-rand可以是:
(define (make-rand)
(define x 0)
(define (set-x! new-x)
(set! x new-x))
(define (dispatch message)
(cond
((eq? message 'generate)
(set! x (rand-update x))
x)
((eq? message 'reset)
set-x!)
(else ((error "Unknown Message - " message)))))
dispatch) ; 'dispatch' returned and assigned to my-rand'reset消息返回一个过程,例如,(my-rand 'reset)返回set-x!,因此((my-rand 'reset) 42)等效于(set-x! 42)。
我们还可以使用lambdas (匿名过程)实现make-rand:
(define (make-rand)
(let ((x 0))
(lambda (message) ; lambda returned and assigned to my-rand
(cond
((eq? message 'generate)
(set! x (rand-update x))
x)
((eq? message 'reset)
(lambda (new-x) (set! x new-x)))
(else ((error "Unknown Message - " message)))))))在这两种情况下,正如奥斯卡所解释的那样,x保持它的价值,因为它不在<proc>/my-rand的范围之内。这一点在第3.2节中作了说明,然后在第4.1节中加以实施。
https://stackoverflow.com/questions/60692547
复制相似问题