我目前正在学习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)
这应强制创建第三个元素,以便为已有2个元素的流调用stream-map
- (1 2)
- 因此它应该生成(2 4)
然后将此结果追加到流中。
为什么此stream-map
始终应用于 last 创建的元素?它是如何工作的?
感谢您的帮助!
答案 0 :(得分:0)
这是一个标准技巧,可以根据前一个元素定义延迟流。将流视为无限的值序列:
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}}。但是当我们去评估流的第三个元素1
时,我们需要知道f(x1)
。幸运的是,我们刚刚评估了x1
,因为它是x1
!这意味着我们可以一次“展开”一个元素的序列,其中每个元素都是根据前一个元素定义的:
f(x0)
这种打结工作是因为流被懒惰地评估,所以每个值都是按需从左到右计算的。因此,每个前一个元素都是在需要后续元素时计算出来的,并且自引用不会导致任何问题。