Functional programming 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 > (

我在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
,以便它只接受一个参数,指示它生成
,或者重置

首先,我试着建立一个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有点令人沮丧的事情之一,有时你需要提前阅读来做练习!最后,我做了一些与你类似的事情,并更新了最初的帖子。