【问题标题】:Clojure: Using a stream without holding head. Is this correct?Clojure:使用不带头的流。它是否正确?
【发布时间】:2023-03-18 02:45:01
【问题描述】:

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

(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 堆空间)

【问题讨论】:

    标签: clojure lazy-sequences


    【解决方案1】:

    您的代码有效。

    这个表格:

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

    【讨论】:

    • 啊,所以 doall 实现了序列,dorun 只是运行它。谢谢。
    猜你喜欢
    • 2011-09-12
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    • 2011-09-19
    • 2011-01-02
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    相关资源
    最近更新 更多