Я хотел бы написать реализацию алгоритму, который создает бесконечную последовательность результатов, где каждый элемент представляет собой вычисление одной итерации алгоритма. Использование ленивой последовательности удобно, поскольку она отделяет логику количества итераций (с помощью take
) и итераций сжигания (с помощью drop
) из реализации.
Здесь приведен пример двух реализаций алгоритмов, один из которых создает ленивую последовательность (yadda-lazy
), а другой - нет (yadda-loop
).
(defn yadda-iter
[v1 v2 v3]
(+ (first v1)
(first v2)
(first v3)))
(defn yadda-lazy
[len]
(letfn [(inner [v1 v2 v3]
(cons (yadda-iter v1 v2 v3)
(lazy-seq (inner (rest v1)
(rest v2)
(rest v3)))))]
(let [base (cycle (range len))]
(inner base
(map #(* %1 %1) base)
(map #(* %1 %1 %1) base)))))
(defn yadda-loop
[len iters]
(let [base (cycle (range len))]
(loop [result nil
i 0
v1 base
v2 (map #(* %1 %1) base)
v3 (map #(* %1 %1 %1) base)]
(if (= i iters)
result
(recur (cons (yadda-iter v1 v2 v3) result)
(inc i)
(rest v1)
(rest v2)
(rest v3))))))
(prn (take 11 (yadda-lazy 4)))
(prn (yadda-loop 4 11))
Есть ли способ создать ленивую последовательность, используя тот же стиль, что и loop
/recur
? Мне нравится yadda-loop
лучше, потому что:
- Это более очевидно, каковы начальные условия и как алгоритм переходит к следующей итерации.
- Из-за оптимизации хвоста он не будет страдать от.