Stream SICP第3.5.2章无限流整数定义

Stream SICP第3.5.2章无限流整数定义,stream,scheme,infinite,sicp,lazy-sequences,Stream,Scheme,Infinite,Sicp,Lazy Sequences,我正在阅读SICP,很难理解为无限流提供的一个示例: 通过使用诸如add streams之类的操作来操作流,我们可以做更多有趣的事情,这会生成两个给定流的元素和:62 现在我们可以如下定义整数: 显然,我能理解整数定义背后的意图,但我正努力在头脑中“模拟”这个流。前面的例子不是问题,因为状态的维护是明确的。例如在本例中: (define (integers-starting-from n) (cons-stream n (integers-starting-from (+ n 1))))

我正在阅读SICP,很难理解为无限流提供的一个示例:

通过使用诸如add streams之类的操作来操作流,我们可以做更多有趣的事情,这会生成两个给定流的元素和:62

现在我们可以如下定义整数:

显然,我能理解
整数定义背后的意图,但我正努力在头脑中“模拟”这个流。前面的例子不是问题,因为状态的维护是明确的。例如在本例中:

(define (integers-starting-from n)
  (cons-stream n (integers-starting-from (+ n 1))))

(define integers (integers-starting-from 1))
我理解整数的这个定义没有问题

这本书描述了
one
的定义:

(定义一个(cons-stream 1个))

这与递归过程的定义非常相似:1是一对,其car为1,其cdr承诺对1进行求值。评估cdr再次给我们一个1和一个评估cdr的承诺,依此类推

也许这句话让我感到厌烦。其中一个很简单,因为在每个
流cdr
上都会评估该过程,并提供一个新的“1”和下一个承诺

当我尝试将此推理应用于
整数时
,我很难理解为什么结果流不是“1 2 2…”,因为整数不断地被重新计算,并且基本上是在1处重新开始

编辑 我没有详细说明在我的问题中是否应该假定回忆录是失职的。SICP确实提到了答案中提出的二次行为问题,并以记忆
延迟
函数的形式提供了解决方案:

(定义(备忘录过程)
(let((已运行?错误)(结果错误))
(lambda()
(如果(尚未运行?)
(开始(设置!结果(过程))
(设置!已运行?为真)
结果)
结果))
然后定义延迟,使(延迟)等于

(备忘录程序(lambda())
请参阅

cons-stream
必须是一种特殊形式。如果
cons-stream
是一个过程,那么根据我们的评估模型,评估
(cons-stream)
将自动导致评估
,这正是我们不希望发生的


我这里缺少的一点是,
整数
根本没有被重新计算。
addstreams
返回的承诺是每个输入流的
stream cdr
。 前面提到的“状态”保持在反馈回路中。

它相当令人费解,老实说,它的力量似乎仍然很神奇

如果我们的流被记忆,那么作为参数传递给
add streams
整数总是“落后于”我们正在枚举的
整数,因此它总是可以访问记忆值。(括号)中的数字表示记忆值的使用:

Integers: 1, add-streams / Ones: 1, 1, 1, 1, 1, 1, ... \Integers: 1, (2), (3), (4), (5), (6), ... === === === === === === Results: 1 2, 3, 4, 5, 6, 7, ... Memoized: 2, 3, 4, 5, 6, 因此,
100
是通过添加
one
99次的元素和
整数的
流车
生成的,该流车是之前99次调用
整数
的结果

虽然第一个
添加流
仅合并两个流,但第二个流(返回
1
后)将返回来自新
添加流
的结果,其中第二个流将是另一个
添加流
的结果:

1, add-streams / 1,               1,               1, ...
               \ 1, add-streams / 1,               1, ...
                                \ 1, add-streams / 1, ...
                                                 \ 1, add-streams ...
因此,
addstreams
,有点像使用
cons
创建一个列表,正在创建一对流,其中第一个是一对流,第二个是另一对流

如果不记忆,这不是整数的实际实现,因为它的性能是O(n^2):

访问元素的时间 CPU时间要素 整数(毫秒) ========== ======== 第一届0 第二名 第四届0 第8届0 第16届0 32街47号 第64届78 128第313条 第256届1171 第512届4500 第1024页17688 2048第66609条 4096第272531页
通过最简单的非记忆流实现,我们得到:

(define (stream-map2 f s1 s2)
  (cons (f (car s1) (car s2)) 
    (lambda ()
      (stream-map2 f ((cdr s1)) ((cdr s2))))))

(define ones (cons 1 (lambda () ones)))

(define integers
    (cons 1 
      (lambda ()
        (stream-map2 + ones integers)))       ;; 1
  = 
    (cons 1 
      (lambda () 
        (cons (+ (car ones) (car integers))
          (lambda () 
            (stream-map2 + ones 
              (stream-map2 + ones integers))))))      ;; 2
  =
    (cons 1 
      (lambda () 
        (cons (+ (car ones) (car integers))
          (lambda () 
            (let ((i2 (stream-map2 + ones integers)))
              (stream-map2 + ones i2))))))
i、 e

=
(缺点1)
(lambda()
(cons(+(car-one)(car-integer))
(lambda()

(让((i2)(cons(+(car-one)(car-integers));;如果你正努力在头脑中模拟它,为什么不用笔和纸(或一些电子等价物)来评估它呢?SICP教给你Scheme使用的评估模型,所以这应该可以机械地进行。如果你已经这样做了,但仍然不理解,你可以指出你没有得到的步骤。用显式状态检查这个替代方案,看看它是否对你更清楚。有时(通常?)同时从两个不同的角度来看问题是有帮助的。我认为这根本不正确。我认为
(取n个整数)
是一个O(n)运算;根据这个答案,它必须是O(n^2)。这是可以测试的。在任何情况下,
cons stream
的特定实现都在使用中(或等价地,
force
)必须根据Scheme的评估规则检查并遵循特定测试代码的评估步骤才能确定。我不再那么确定了。我已经添加了答案,但需要完成…我测试了性能,没有记忆,它是二次的。我还验证了在访问第n个元素
add streams时
被调用n次。(正如预期的那样,因为
整数
调用
添加流
,但是
整数
也是
添加流
的参数之一)对吧。事实上,对于非记忆流来说,看起来像
的流和
整数都是重新输入的。这样做很累
integers                          1
    ones                              1,  1,  1,  1,  1,  1,  ...
    integers                          1
        ones                              1,  1,  1,  1,  1,  ...
        integers                          1
            ones                              1,  1,  1,  1,  ...
            integers                          1
                ones                              1,  1,  1,  ...
                integers                          1
                    ones                              1,  1,  ...
                    integers                          1
                        ones                              1,  ...
                        integers                          1
                                 ==  ==  ==  ==  ==  ==  ==  
                                  1,  2,  3,  4,  5,  6,  7,  ...
1, add-streams / 1,               1,               1, ...
               \ 1, add-streams / 1,               1, ...
                                \ 1, add-streams / 1, ...
                                                 \ 1, add-streams ...
Time to Access Elements Element of CPU Time integers (msec) ========== ======== 1 st 0 2 nd 0 4 th 0 8 th 0 16 th 0 32 nd 47 64 th 78 128 th 313 256 th 1,171 512 th 4,500 1,024 th 17,688 2,048 th 66,609 4,096 th 272,531
(define (stream-map2 f s1 s2)
  (cons (f (car s1) (car s2)) 
    (lambda ()
      (stream-map2 f ((cdr s1)) ((cdr s2))))))

(define ones (cons 1 (lambda () ones)))

(define integers
    (cons 1 
      (lambda ()
        (stream-map2 + ones integers)))       ;; 1
  = 
    (cons 1 
      (lambda () 
        (cons (+ (car ones) (car integers))
          (lambda () 
            (stream-map2 + ones 
              (stream-map2 + ones integers))))))      ;; 2
  =
    (cons 1 
      (lambda () 
        (cons (+ (car ones) (car integers))
          (lambda () 
            (let ((i2 (stream-map2 + ones integers)))
              (stream-map2 + ones i2))))))
  = 
    (cons 1 
      (lambda () 
        (cons (+ (car ones) (car integers))
          (lambda () 
            (let ((i2 (cons (+ (car ones) (car integers))   ;; <---- 1
                        (lambda () 
                          (stream-map2 + ones 
                            (stream-map2 + ones integers))))))
              (cons (+ (car ones) (car i2))
                (lambda ()
                  (stream-map2 + ones ((cdr i2))))))))))
  = 
    (cons 1 
      (lambda () 
        (cons (+ (car ones) (car integers))
          (lambda () 
            (cons (+ (car ones) 
                     (+ (car ones) (car integers)))
              (lambda ()
                (stream-map2 + ones 
                  (stream-map2 + ones 
                    (stream-map2 + ones integers)))))))))     ;; 3
  =
    ....