Ответ 1
Ваша версия цикла будет лучше написана для (1) вытащить добавление из цикла, чтобы вам не приходилось повторять так много последовательностей и (2) использовать conj
на векторном аккумуляторе, чтобы ваши результаты были в том же порядке, что и ваш yadda-lazy
.
(defn yadda-loop-2 [len iters]
(let [v1 (cycle (range len))
v2 (map * v1 v1)
v3 (map * v1 v2)
s (map + v1 v2 v3)]
(loop [result [], s s, i 0]
(if (= i iters)
result
(recur (conj result (first s)), (rest s), (inc i))))))
Однако в этот момент становится ясно, что цикл бесполезен, поскольку это просто
(defn yadda-loop-3 [len iters]
(let [v1 (cycle (range len))
v2 (map * v1 v1)
v3 (map * v1 v2)
s (map + v1 v2 v3)]
(into [] (take iters s))))
и мы могли бы также вытащить параметр iters
, вернуть просто s
и take
с него.
(defn yadda-yadda [len]
(let [v1 (cycle (range len))
v2 (map * v1 v1)
v3 (map * v1 v2)]
(map + v1 v2 v3)))
Это дает те же результаты, что и ваш yadda-lazy
, также ленив и довольно ясен
(take 11 (yadda-yadda 4)) ;=> (0 3 14 39 0 3 14 39 0 3 14)
Вы также могли бы, эквивалентно
(defn yadda-yadda [len]
(as-> (range len) s
(cycle s)
(take 3 (iterate (partial map * s) s))
(apply map + s)))
добавление
Если вы ищете шаблон для преобразования нетерпеливого цикла, подобного вашему, в ленивую последовательность
-
(loop [acc [] args args]...)
→((fn step [args]...) args)
-
(if condition (recur...) acc)
→(when condition (lazy-seq...)
-
(recur (conj acc (f...))...)
→(lazy-seq (cons (f...) (step...)))
Применяя это к вашему yadda-lazy
(defn yadda-lazy-2 [len iters]
(let [base (cycle (range len))]
((fn step [i, v1, v2, v3]
(when (< i iters)
(lazy-seq
(cons (yadda-iter v1 v2 v3)
(step (inc i), (rest v1), (rest v2), (rest v3))))))
0, base, (map #(* %1 %1) base), (map #(* %1 %1 %1) base))))
И в этот момент вы, вероятно, хотите, чтобы вытащить iters
(defn yadda-lazy-3 [len]
(let [base (cycle (range len))]
((fn step [v1, v2, v3]
(lazy-seq
(cons (yadda-iter v1 v2 v3)
(step (rest v1), (rest v2), (rest v3)))))
base, (map #(* %1 %1) base), (map #(* %1 %1 %1) base))))
Так что вы можете
(take 11 (yadda-lazy-3 4)) ;=> (0 3 14 39 0 3 14 39 0 3 14)
И тогда вы могли бы сказать: эй, мой yadda-iter
просто применяет +
на первом, а step
применяется к остальным, так почему бы не объединить мои v1, v2, v3
и сделать это немного яснее?
(defn yadda-lazy-4 [len]
(let [base (cycle (range len))]
((fn step [vs]
(lazy-seq
(cons (apply + (map first vs))
(step (map rest vs)))))
[base, (map #(* %1 %1) base), (map #(* %1 %1 %1) base)])))
И вот, вы только что переделали вариационную карту
(defn yadda-lazy-5 [len]
(let [base (cycle (range len))]
(map + base, (map #(* %1 %1) base), (map #(* %1 %1 %1) base))))