Functional programming SICP 3.6-随机过程和局部状态变量
我在SICP的练习3.6中遇到困难。 它们给出了伪随机数生成器的以下代码:Functional programming SICP 3.6-随机过程和局部状态变量,functional-programming,scheme,sicp,Functional Programming,Scheme,Sicp,我在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 > (
(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
,以便它只接受一个参数,指示它生成,或者重置
首先,我试着建立一个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表达式移动到Condition中的操作如下:
(define (rand-new instruction)
(cond ((eq? instruction 'generate)
(let ((x random-init))
(lambda ()
(set! x (rand-update x))
x)))))
那么,为什么第一个函数起作用,而新函数不起作用呢?
这与使用条件有关吗?还是添加了一个参数
更新(20年3月19日)
阅读下一节关于计算环境模型的内容(§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))
理解为什么第一个版本有效(而另一个版本无效)的关键点在于前三行:
(define rand
(let ((x random-init))
(lambda ()
如您所见,名称rand
被分配给lambda
——但在此之前,在lambda
之外的范围内创建变量x
,这意味着:无论我们调用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
,请尝试将过程分开(正如我在上面所做的),如果您将所有内容放在一个地方,很快事情就会变得混乱。理解为什么第一个版本有效(为什么另一个版本无效)的关键点在前三行:
(define rand
(let ((x random-init))
(lambda ()
如您所见,名称rand
被分配给lambda
——但在此之前,在lambda
之外的范围内创建变量x
,这意味着:无论我们调用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
,请尝试将过程分开(正如我在上面所做的),如果您将所有内容放在一个地方,很快事情就会变得混乱。x
不包含在我们的“random”过程中<代码>x
包含在我们的“随机”过程中。溶液的形状为:
(define (make-rand)
(define x 0)
...
<proc>)
(define my-rand (make-rand))
((my-rand 'reset) 42)
(my-rand 'generate)
(my-rand 'generate)
'reset
消息返回一个过程,例如,(my rand'reset)
返回set-x
因此((我的兰德重置)42)
相当于(set-x!42)
我们还可以使用lambdas(匿名过程)实现make rand
:
在任何一种情况下,正如Oscar解释的那样,x
保持它的价值,因为它不在
/my rand
的范围之内。这在§3.2中描述,然后在§4.1中实施。x
不包含在我们的“随机”程序中<代码>x
包含在我们的“随机”过程中。溶液的形状为:
(define (make-rand)
(define x 0)
...
<proc>)
(define my-rand (make-rand))
((my-rand 'reset) 42)
(my-rand 'generate)
(my-rand 'generate)
'reset
消息返回一个过程,例如,(my rand'reset)
返回set-x
因此((我的兰德重置)42)
相当于(set-x!42)
我们还可以使用lambdas(匿名过程)实现make rand
:
在任何一种情况下,正如Oscar解释的那样,
x
保持它的价值,因为它不在
/my rand
的范围之内。这在§3.2中有描述,然后在§4.1中实施。“虽然我不明白为什么会这样”->那么,在尝试修改它之前,您需要花时间理解它为什么会这样!“虽然我不明白为什么会这样”->那么,在尝试修改它之前,您需要花时间理解它为什么会这样!谢谢-事实上,必要的理论最终被包含在§3.2中。这是关于SICP有点令人沮丧的事情之一,有时你需要提前阅读来做练习!最后,我做了一些与你类似的事情,并更新了最初的帖子。谢谢-事实上,必要的理论最终被包含在§3.2中。这是关于SICP有点令人沮丧的事情之一,有时你需要提前阅读来做练习!最后,我做了一些与你类似的事情,并更新了最初的帖子。