整理你的功能。
由於@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] ...)
... - 三個參數的簡單功能。
處理底層問題。
你的功能有兩個問題:
步履維艱
閃爍的紅燈在這個函數是
(fn [acc item] (conj acc (func (last acc) item)))
使用last
這會掃描整個的每次調用時間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 ...
注意,你可以使用'秒':'(第二[3 4 5])''是4'。 – bfontaine 2014-09-06 07:12:55
您可能會發現有趣的[此博客](http://blog.jayfields.com/2010/07/clojure-destructuring.html)。 – Mark 2014-09-06 09:44:08