【问题标题】:How Racket streams work in this case?在这种情况下,Racket 流如何工作?
【发布时间】:2018-06-16 19:47:29
【问题描述】:

我目前正在学习 Racket(只是为了好玩),我偶然发现了这个例子:

(define doubles
   (stream-cons
     1
     (stream-map 
        (lambda (x) 
            (begin
                (display "map applied to: ")
                (display x)
                (newline)
                (* x 2)))
        doubles)))

它产生 1 2 4 8 16 ...

我不太明白它是如何工作的。

所以它创建 1 作为第一个元素;当我调用 (stream-ref doubles 1) 时,它会创建第二个元素,显然是 2

然后我调用(stream-ref doubles 2),它应该强制创建第三个元素,所以它为已经有两个元素的流调用stream-map——(1 2)——所以它应该产生(2 4)然后将这个结果附加到流中.

为什么这个stream-map 总是应用于last 创建的元素?它是如何工作的?

感谢您的帮助!

【问题讨论】:

标签: stream scheme racket self-reference sicp


【解决方案1】:

这是一个标准技巧,可以根据之前的元素定义惰性流。将流视为无限的值序列:

s = x0, x1, x2, ...

现在,当您在流上map 时,您提供一个函数并生成一个新流,该函数应用于流的每个元素:

map(f, s) = f(x0), f(x1), f(x2), ...

但是,当流根据自身的映射定义时会发生什么?好吧,如果我们有一个流s = 1, map(f, s),我们可以扩展该定义:

s = 1, map(f, s)
  = 1, f(x0), f(x1), f(x2), ...

现在,当我们实际去计算流的第二个元素f(x0),那么x0 显然是1,因为我们将流的第一个元素定义为1。但是当我们去评估流的第三个元素f(x1)时,我们需要知道x1。幸运的是,我们刚刚评估了x1,因为它是f(x0)!这意味着我们可以一次“展开”序列一个元素,其中每个元素都根据前一个元素定义:

f(x) = x * 2

s = 1, map(f, s)
  = 1, f(x0), f(x1), f(x2), ...
  = 1, f(1),  f(x1), f(x2), ...
  = 1, 2,     f(x1), f(x2), ...
  = 1, 2,     f(2),  f(x2), ...
  = 1, 2,     4,     f(x2), ...
  = 1, 2,     4,     f(4),  ...
  = 1, 2,     4,     8,     ...

这种打结是有效的,因为流是懒惰地评估的,所以每个值都是按需计算的,从左到右。因此,每个前一个元素在请求后一个元素时都已计算完毕,自引用不会造成任何问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    • 2017-06-21
    • 2018-01-19
    • 1970-01-01
    • 2021-12-06
    • 2020-12-27
    • 2021-08-31
    相关资源
    最近更新 更多