functional-programming - SICP 3.6 - 兰德过程和局部状态变量
问题描述
我在 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
or '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))
解决方案
理解第一个版本为什么有效(以及为什么另一个不有效)的关键在于前三行:
(define rand
(let ((x random-init))
(lambda ()
如您所见,名称rand
被分配给- 但在此之前,会在之外的范围内创建lambda
一个变量,这意味着:无论我们调用多少次, 中的值都会“记住”其先前的值,即我们在之前的调用中设置:.x
lambda
rand
x
(set! x (rand-update x))
因此,您必须尊重 thatlet
和 that的位置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
,试着把这些过程分开(就像我上面做的那样),如果你把所有东西都放在一个地方,事情很快就会变得混乱。
推荐阅读
- asp.net-mvc - EntityType 没有在 postgres 存储函数调用上定义键
- android - 如何限制 WifiDirect 的可见性?
- mysql - 当我在 mysql 中有一个子句时如何选择前几行?
- html - 如何仅使用 HTML + CSS 更改图像
- c - 再次在 Unix 中使用递归管道第 2 部分
- botframework - 自定义 Microsoft 网络聊天
- javascript - 当事件未在 jquery 中设置时做某事
- r - R 正则表达式重复
- java - Wicket DropDownChoice 只读
- javascript - NaN超出行列式函数?