
8.3 Бесконечные потоки
Мы рассмотрели хотя и большие, но все-таки ограниченные последовательности данных.
Теперь с помощью потоков попробуем рассмотреть и бесконечные последовательности или, как их обычно называют, - бесконечные потоки.
Дадим LISP-определение, к примеру, бесконечной последовательности единиц:
> (define ones (cons-stream 1 ones))
Это определение выглядит так же, как и определение потока. Его единственное и основное отличие в процедуре получения определяемого значения: поток ничем не ограничен и, следовательно, - бесконечен.
В самом деле, вызов ones возвратит пару, из единицы и обещания вычислить ones, которое, в свою очередь, вызовет … и т.д. и т.п.
Вот мы и получили бесконечный поток единиц.
Естественно, работа с бесконечными потоками требует определённой осторожности.
Так, попытка вычислить длину такого потока приведёт к зацикливанию программы. Однако, если обращаться только к конечному числу элементов, работа даже с бесконечными потоками практически не будет отличается от работы со списками.
> (elem-no 5 ones)
1
Определим функцию заполнения бесконечного потока целочисленными значениями, начиная с n
> (define (integers-from n)
(cons-stream n (integers-from (+ n 1))))
Теперь определим величину ints как бесконечный поток, заполненный целочисленными значениями начиная с 10
> (define ints (integers-from 10))
И найдем его 5-тый элемент
> (elem-no 5 ints)
14
Поскольку применение функции stream->list к бесконечным потокам бессмысленно, мы определим похожую функцию, скажем initial, возвращающую список из первых n элементов потока.
Это NIL !!
> (define (initial n S)
(if (= n 0) (list)
(cons (head S)
(initial (- n 1) (tail S)))))
>(initial 5 ints)
(10 11 12 13 14)
А теперь – посмотрим на замечательное сложение:
> (initial 5 (stream-add ints ones))
(11 12 13 14 15)
Можно определить на обычных потоках функцию map:
> (define (stream-map proc S)
(if (empty-stream? S) empty-stream
(cons-stream (proc (head S))
(stream-map proc (tail S)))))
И теперь, какая-либо заданная функция proc может работать и на бесконечном потоке. Например, предварительно вспомнив описание sqr, можем получить квадраты элементов бесконечного потока
> (initial 5 (stream-map sqr ints))
(100 121 144 169 196)
Вот определение функции фильтрации на потоках:
> (define (stream-filter pred S)
(cond ((empty-stream? S) empty-stream)
((pred (head S))
(cons-stream (head S)
(stream-filter pred
(tail S))))
(else (stream-filter pred (tail S)))))
Пример получения из бесконечного потока ints (начиная с 10) только 7-ми четных чисел:
> (initial 7 (stream-filter even? ints))
(10 12 14 16 18 20 22)