Clojure: Использование потока без удерживания головы. Это правильно?
Я хочу поместить ленивую последовательность где-нибудь, чтобы предоставить данные по мере необходимости. Я знаю, что должен избегать удержания главы последовательности. Я придумал следующее решение, я что-то упустил?
(defn headless [s]
(let [a (atom s)]
(fn
([] (let [s @a r (first s)]
(swap! a rest) r))
([n] (let [s @a rs (take n s)]
(swap! a #(drop n %)) rs)))))
Например, этот простой генератор просто дает натуральные числа.
(def nums (headless (iterate inc 0)))
(nums 5)
; (0 1 2 3 4)
(nums)
;5
Обновление: "тест" должен использовать дорун, а не доалл. Посмотреть решение от lgrapenthin
(Не слишком реалистичный) тест с
(doall (map #(nums %) (repeat 20)))
произошел сбой через 5 минут использования всех 4 ядер с исключением (OutOfMemoryError пространство кучи Java)
1 ответ
Ваш код работает.
Эта форма:
(doall (map #(nums %) (repeat 20)))
будет генерировать бесконечное количество (чисел 20) и никогда не вернется. Ты можешь использовать dorun
вместо этого, чтобы отбросить сгенерированный (nums 20)
и не хранить их в памяти. Тем не менее, он не вернется, потому что (repeat 20)
генерирует бесконечную ленивую последовательность
Чуть более читаемая версия headless
(defn headless [s]
(let [a (atom s)]
(fn
([] (let [s @a]
(swap! a rest)
(first s))
([n] (let [s @a]
(swap! a (partial drop n))
(take n s)))))))