0

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

(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)))

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

4

1 回答 1

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)))))))
于 2013-09-11T19:02:12.227 回答