首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

惰性编程和惰性求值(2)

惰性编程和惰性求值(2)

不确定列表假设您有一个由 5 的倍数组成的列表。现在您希望计算这个列表中所有数字的平方。最后,我们希望对计算结果进行遍历,并显示所有平方值小于 500 的数字。什么?您不能对一个无穷列表进行操作?为什么不行呢?
实际上,可能与直观的感觉相反,如果无穷列表基于一定的生成规则 ,那么无穷列表可能比有穷列表存储起来占用的空间更少。在上面这个例子中,原始列表是基于 X = (i + 1) * 5 这条规则生成的,其中 X 是列表在索引 i 处的值。 X 也可以使用其前一个值来表示:X = X[i-1] + 5; X[0] = 5。使用 Scheme 的 force 和 delay,就可以构造一个基于这条规则的数值
清单 5. 流的例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
;This is the generative rule for the list. It returns a pair
;with the car being the next value, and the cdr being a promise
;for the next pair
(define (my-generative-rule last-val)
        (let (
              ;generative formula based on previous value
              (next-val (+ last-val 5)))
          ;put the next value together with a promise for another one
          (cons next-val (delay (my-generative-rule next-val)))))
;Since the cdr is a promise of a pair, rather than a pair itself,
;we have our own functions for getting the car and cdr.
(define (mystream-car the-stream) (car the-stream))
(define (mystream-cdr the-stream) (force (cdr the-stream)))

;Create our list
(define multiples-of-five (cons 5 (delay (my-generative-rule 5))))

;Display the fourth element of the list
(display (mystream-car (mystream-cdr (mystream-cdr (mystream-cdr multiples-of-five)))))
(newline)




现在,您希望计算所有数字的平方。要实现这种功能,需要一个函数从现有流和生成规则中创建一个新流 —— 这有点像 map,只不过它是针对流进行的。函数如下:
清单 6. 流的专用映射
1
2
3
4
5
6
7
8
9
10
11
12
(define (mystream-map function the-stream)
  (cons
    ;;The first value will be the function applied to the car
    (function (car the-stream))
    ;;The remaining values will be stored in a promise
    (delay (mystream-map function (mystream-cdr the-stream)))))

(define squared-stream (mystream-map (lambda (x) (* x x)) multiples-of-five))

;Display the fourth element of this new list
(display (mystream-car (mystream-cdr (mystream-cdr (mystream-cdr squared-stream)))))
(newline)




现在,剩下的问题就是循环遍历该流,并打印结果值小于 500 的值:
清单 7. 循环遍历流
1
2
3
4
5
6
7
8
(let loop (
           (remaining-stream squared-stream))
  (if (>= (mystream-car remaining-stream) 500)
      #f
      (begin
        (display (mystream-car remaining-stream))
        (newline)
        (loop (mystream-cdr remaining-stream)))))




显然,对于这种小程序来说,还有很多方法都可以更直接地实现这个目标。然而,即使在这个例子中,流也可以帮助我们较少地从实现角度来审视问题,而是更多地将问题当作一种抽象思想来看待。流让我们可以集中精力在问题 上,而不是在实现 上。流简化了与生成元素有关的算法的概念和实现。
到目前为止,我们所讨论的流对于学习流背后的概念来说都非常有用。然而,实现却可能会经受大量缺陷的折磨。首先,在很多场合下流都可能需要一个终结器。这种实现却并没有提供这种机制。另外,此处给出的这种流称为 odd stream,这种形式的流很容易实现。  但是这种流可能会导致所执行的计算量比所希望的多,因为列表中的值都会进行计算。标准流是在 SRFI-40 中定义的,它解决了这些问题以及其他一些问题(更多细节请参看 )。
返回列表