SICP 3.6 - Rand 过程和局部状态变量
SICP 3.6 - Rand procedure and local state variables
我在 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
.
首先,我尝试设置一个具有生成条件的兰特。然而,我在这第一个障碍上绊倒了。
(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))
理解为什么第一个版本有效(以及为什么另一个不有效)的关键点在前三行:
(define rand
(let ((x random-init))
(lambda ()
如您所见,名称 rand
被分配给 lambda
- 但在此之前,变量 x
在范围 outside[ lambda
的=36=],意思是:无论我们调用rand
多少次,x
中的值都会"remember"它之前的值,我们在上一个电话:(set! x (rand-update x))
。
因此,您必须尊重 let
和 lambda
的位置,否则您创建的过程将没有任何 "memory" 在调用之间。此外,我不认为练习要求您创建自己的 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
包含在使我们的'random'程序的程序中。解的形状为:
(define (make-rand)
(define x 0)
...
<proc>)
(define my-rand (make-rand))
((my-rand 'reset) 42)
(my-rand 'generate)
(my-rand 'generate)
所以 make-rand
returns 一个过程 <proc>
其中:
- 给定消息
'generate
returns下一个随机数。
- 给定消息
'reset
returns 另一个 过程接受新值并将其分配给 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
消息 returns 一个过程,例如 (my-rand 'reset)
returns 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)))))))
无论哪种情况,正如 Oscar 解释的那样,x
保持其价值,因为它在 <proc>
/my-rand
的范围之外。这在 §3.2 中描述,然后在 §4.1 中实现。
我在 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
.
首先,我尝试设置一个具有生成条件的兰特。然而,我在这第一个障碍上绊倒了。
(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))
理解为什么第一个版本有效(以及为什么另一个不有效)的关键点在前三行:
(define rand
(let ((x random-init))
(lambda ()
如您所见,名称 rand
被分配给 lambda
- 但在此之前,变量 x
在范围 outside[ lambda
的=36=],意思是:无论我们调用rand
多少次,x
中的值都会"remember"它之前的值,我们在上一个电话:(set! x (rand-update x))
。
因此,您必须尊重 let
和 lambda
的位置,否则您创建的过程将没有任何 "memory" 在调用之间。此外,我不认为练习要求您创建自己的 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
包含在使我们的'random'程序的程序中。解的形状为:
(define (make-rand)
(define x 0)
...
<proc>)
(define my-rand (make-rand))
((my-rand 'reset) 42)
(my-rand 'generate)
(my-rand 'generate)
所以 make-rand
returns 一个过程 <proc>
其中:
- 给定消息
'generate
returns下一个随机数。 - 给定消息
'reset
returns 另一个 过程接受新值并将其分配给 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
消息 returns 一个过程,例如 (my-rand 'reset)
returns 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)))))))
无论哪种情况,正如 Oscar 解释的那样,x
保持其价值,因为它在 <proc>
/my-rand
的范围之外。这在 §3.2 中描述,然后在 §4.1 中实现。