Clojure:使用没有头部的流。它是否正确?

时间:2013-09-11 18:38:08

标签: clojure lazy-sequences

我想在某处放置一个惰性序列以根据需要提供数据。我知道我必须避免保持序列的头部。我提出了以下解决方案,我错过了什么吗?

(defn headless [s] 
  (let [a (atom s)] 
    (fn 
      ([]  (let [s @a r (first s)] 
             (swap! a rest) r)) 
      ([n] (let [s @a rs (take n s)] 
             (swap! a #(drop n %)) rs))))) 

用法示例,这个简单的生成器只给出了自然数。

(def nums (headless (iterate inc 0)))

(nums 5)
; (0 1 2 3 4)

(nums)
;5

更新:“测试”应该使用dorun,而不是doall。请参阅lgrapenthin的解决方案

使用

进行(不过于逼真)测试
(doall (map #(nums %) (repeat 20)))

使用异常(OutOfMemoryError Java堆空间)使用所有4个核心5分钟后崩溃

1 个答案:

答案 0 :(得分:2)

您的代码有效。

此表格:

(doall (map #(nums %) (repeat 20)))

将产生无限量(nums 20)并且永不返回。您可以使用dorun来删除生成的(nums 20),而不是将其保留在内存中。但是,它不会返回,因为(repeat 20)生成一个无限的懒惰序列。

headless

的可读性略高
(defn headless [s] 
  (let [a (atom s)] 
    (fn 
      ([]  (let [s @a]
             (swap! a rest)
             (first s))
      ([n] (let [s @a]
             (swap! a (partial drop n))
             (take n s)))))))