Уборка вашей функции.
Как @bfontaine комментировал, вы можете использовать (second args)
вместо (first (rest args))
:
(defn reductions [func & args]
(reduce
(fn [acc item] (conj acc (func (last acc) item)))
[(first args)]
(second args)))
Это использует
func
(first args)
(second args)
... но игнорирует остальную часть args
.
Таким образом, мы можем использовать деструктурирующие назвать первый и второй элементы args
- init
и coll
кажется подходящим - давая
(defn reductions [func & [init coll & _]]
(reduce
(fn [acc item] (conj acc (func (last acc) item)))
[init]
coll))
... где _
это условное название для игнорировали аргумент, в этом случае последовательность.
Мы можем избавиться от него, упрощая для
(defn reductions [func & [init coll]] ...)
... а затем
(defn reductions [func init coll] ...)
... - прямолинейная функция трех аргументов.
Работа с основными проблемами.
Ваша функция имеет две проблемы:
- медленность
- отсутствие лени.
Медлительность
мигающий красный свет в этой функции является использование last
в
(fn [acc item] (conj acc (func (last acc) item)))
Это сканирует всю acc
каждый раз, когда она называется, даже если acc
является вектор. Таким образом, это reductions
занимает время пропорционально квадратных длины coll
: безнадежно медленно для длинных последовательностей.
Простым решением является замена (last acc)
на (acc (dec (count acc)))
, который принимает эффективное постоянное время.
Отсутствие лени
Мы еще не можем использовать то, что лениво производит функцию. Например, было бы неплохо, чтобы инкапсулировать последовательность факториалов так:
(def factorials (reductions * 1N (next (range)))))
с вашим reductions
, это определение никогда не возвращается.
Вы должны полностью переделать свою функцию, чтобы сделать ее ленивой. Давайте изменим стандартную -lazy - reductions
использовать деструктурирующие:
(defn reductions [f init coll]
(cons
init
(lazy-seq
(when-let [[x & xs] (seq coll)]
(reductions f (f init x) xs)))))
Теперь мы можем определить
(def factorials (reductions * 1N (next (range))))
Тогда, например,
(take 10 factorials)
;(1N 1N 2N 6N 24N 120N 720N 5040N 40320N 362880N)
Другой подход заключается в получении последовательность из себя, как железнодорожный локомотив, на котором проходит дорожка:
(defn reductions [f init coll]
(let [answer (lazy-seq (reductions f init coll))]
(cons init (map f answer coll))))
Но это содержит скрытую рекурсию (скрытый от меня, по крайней мере):
(nth (reductions * 1N (next (range))) 10000)
;StackOverflowError ...
Примечание вы можете использовать 'second':' (второй [3 4 5]) '' является 4'. – bfontaine
Вы можете найти интересный [этот блог] (http://blog.jayfields.com/2010/07/clojure-destructuring.html). – Mark