Итак, мы хотим построить infinite-stream
, который преобразует список элементов в поток элементов, который бесконечно повторяет список ввода.
;; infinite-stream :: list -> stream
(define (infinite-stream xs)
...)
Давайте также напишем несколько примеров, чтобы напомнить нам, как все должно происходить работа:
(stream->list (stream-take (infinite-stream (list 1 2 3)) 10))
;; expect (list 1 2 3 1 2 3 1 2 3 1)
Аргументом является список xs
, поэтому, как обычно, есть две возможности: либо empty
, либо cons
. Следовательно, мы можем выполнить анализ случая.
;; infinite-stream :: list -> stream
(define (infinite-stream xs)
(cond
[(empty? xs) ...]
[else ;; here we have (first xs) and (rest xs) available
...]))
Что мы должны делать в базовом случае, когда xs
равно empty
? Давайте посмотрим на наш пример. В какой-то момент (infinite-stream (list 1 2 3))
вызовет (infinite-stream (list 2 3))
, что вызовет (infinite-stream (list 3))
, а затем вызовет (infinite-stream (list))
. Но сейчас мы застряли! На данный момент мы все еще хотим генерировать бесконечно больше элементов, но у нас нет никакой информации, которую мы могли бы использовать вообще, потому что аргумент просто empty
. Данные 1
, 2
и 3
нам недоступны, но мы нуждаемся в них для продолжения процесса.
Итак, давайте предположим, что мы волшебным образом имеем очень оригинальные данные orig-xs
доступно для нас (и давайте переименуем функцию в infinite-stream-helper
):
;; infinite-stream-helper :: list, list -> stream
(define (infinite-stream-helper xs orig-xs)
(cond
[(empty? xs) ...]
[else ;; here we have (first xs) and (rest xs) available
...]))
Значение infinite-stream-helper
заключается в следующем: создать бесконечный поток повторяющихся элементов из orig-xs
, но в первом » round ", вместо этого используйте элементы из xs
.
Вот несколько примеров:
(stream->list (stream-take (infinite-stream-helper (list) (list 1 2 3)) 10))
;; expect (list 1 2 3 1 2 3 1 2 3 1)
(stream->list (stream-take (infinite-stream-helper (list 3) (list 1 2 3)) 10))
;; expect (list 3 1 2 3 1 2 3 1 2 3)
(stream->list (stream-take (infinite-stream-helper (list 2 3) (list 1 2 3)) 10))
;; expect (list 2 3 1 2 3 1 2 3 1 2)
(stream->list (stream-take (infinite-stream-helper (list 1 2 3) (list 1 2 3)) 10))
;; expect (list 1 2 3 1 2 3 1 2 3 1)
Теперь можно написать базовый вариант! Я оставлю вас, чтобы заполнить его. Подсказка: каким должен быть результат (infinite-stream-helper (list) (list 1 2 3))
? Как этот результат связан с результатом (infinite-stream-helper (list 1 2 3) (list 1 2 3))
?
Теперь, что для рекурсивного случая, что мы должны делать? Давайте посмотрим на пример. Предположим теперь, что мы имеем дело с (infinite-stream-helper (list 2 3) (list 1 2 3))
, что должно привести к потоку 2 3 1 2 3 1 2 3 ...
.
Это просто помещает 2
перед потоком 3 1 2 3 1 2 3 ...
. Мы знаем, как построить поток 3 1 2 3 1 2 3 ...
? Да! Это просто (infinite-stream-helper (list 3) (list 1 2 3))
!
;; infinite-stream-helper :: list, list -> stream
(define (infinite-stream-helper xs orig-xs)
(cond
[(empty? xs) ... FILL THIS IN ...]
[else (stream-cons (first xs) (infinite-stream-helper (rest xs) orig-xs))]))
Но мы еще не закончили. То, что мы изначально хотим, это infinite-stream
, а не infinite-stream-helper
, но теперь должно быть легко определить infinite-stream
из infinite-stream-helper
.
;; infinite-stream :: list -> stream
(define (infinite-stream xs)
... FILL THIS IN ...)