Я только что заметил, что @Carciginate добавил решение, основанное на iterate
, к принятому ответу примерно за двенадцать часов до того, как я опубликовал следующий.
Нет необходимости настраивать специальные функции для управления потоками. Стандартные функции последовательности предназначены для манипулирования всем, что соответствует интерфейсу последовательности.
Ваши определения
(defn stream-car [stream] (first stream))
(defn stream-cdr [stream] (rest stream))
... может быть проще выражено как
(def stream-car first)
(def stream-cdr rest)
Другими словами,
stream-car
является синонимом first
stream-cdr
является синонимом rest
.
Точно так же, ваш cons-stream
по сути копирует старый lazy-cons
, который теперь устарел.
Ваша функция stream-map
ничего не добавляет к стандартному map
, который уже ленив. это также предполагает, что только первая последовательность может иссякнуть.
В любом случае, вам не нужно map
здесь. Лучше всего подходит iterate
, который можно определить как
(defn iterate [f x]
(lazy-seq (cons x (iterate f (f x)))))
Затем мы можем определить ваш sqrt-stream
как
(defn sqrt-stream [x]
(iterate
(fn [guess] (sqrt-improve guess x))
1.0))
Например,
=> (take 10 (sqrt-stream 10))
(1.0 5.5 3.659090909090909 3.196005081874647 3.16245562280389
3.162277665175675 3.162277660168379 3.162277660168379
3.162277660168379 3.162277660168379)
Есть проблемы, которые растягивают репертуар последовательности Clojure, но это не одна из них.
Извините, что выгляжу таким негативным, но при разработке Clojure было уделено немало усилий, чтобы избежать репликации функций последовательности, к которым были склонны некоторые предыдущие Lisps.