当一个函数被赋予一个大的延迟seq时,避免保留头部是有益的,这样如果完全实现的序列不适合内存,你仍然可以处理它。例如,这很好用:
(count (take 10000000 (range)))
(reduce + (take 10000000 (range)))
但这会产生内存不足错误:
(defn recount [coll n]
[(count (take n coll))
(reduce + (take n coll))])
(recount (range) 10000000)
因为当计数实现了懒惰的序列时,coll的绑定会保留序列的头部。
我能想出的最接近的东西是一个强制重新评估seq而不是绑定的宏:
(defmacro recount4 [coll n]
`[(count (take ~n ~coll))
(reduce + (take ~n ~coll))])
(recount4 (range) 10000000)
这似乎没有广泛适用。
我看了this blog,但由于原子和可变状态的使用,解决方案不太令人满意。
答案 0 :(得分:5)
您可能希望查看eduction - 它会创建一个延迟的,非缓存的顺序集合,并将通过缩减重新评估每次使用的完整集合。
答案 1 :(得分:0)
你想要的是eduction。
它允许对集合进行迭代或缩减。它在大多数情况下都像一个集合,但没有实现潜在的懒惰seq。
但是, count
不适用于教育,因此我们必须重写count
作为缩减。
(defn recount5 [coll n]
(let [s (eduction (take n) coll)]
[(reduce (fn [r x] (inc r)) 0 s)
(reduce + s)]))
(recount5 (range) 10000000)