2013-06-26 34 views
3

未实现懒-seq的一步,我有一个懒序列,其中每个项目需要一定的时间来计算:我可以处理的步骤

(defn gen-lazy-seq [size] 
    (for [i (range size)] 
    (do 
     (Thread/sleep 1000) 
     (rand-int 10)))) 

是否有可能评估一步此序列步骤并打印结果。当我试着使用fordoseq Clojure的处理总是实现整体懒-seq的打印任何东西之前:

(doseq [item (gen-lazy-seq 10)] 
    (println item)) 

(for [item (gen-lazy-seq 10)] 
    (println item)) 

两个表达式将等待10秒打印任何东西之前。我曾将doall和dorun看作解决方案,但他们要求lazy-seq生成函数包含println。我想分别定义一个lazy-seq生成函数和lazy-seq打印函数,并使它们逐项地一起工作。

试图执行此操作的动机: 我有通过网络进入的消息,并且我希望在收到所有消息之前开始处理它们。同时,将所有对应于查询的消息保存在lazy-seq中将会很好。

编辑1:

JohnJ的回答显示了如何创建一个懒惰-seq的,将被评估一步一步来。我想知道如何逐步评估任何懒惰seq。

我很困惑,因为在上面定义的gen-lazy-seq上运行(chunked-seq? (gen-lazy-seq 10)),或者如JohnJ的答案中定义的那样都返回false。那么问题不可能是一个创建了一个分块的序列,另一个没有。

this答案中,显示了将分块lazy-seq变成非分块的函数的函数seq1。尝试该功能仍然会导致延迟输出的相同问题。我想,也许延迟已与某种在REPL缓冲要做,所以我试图同时打印时在SEQ每个项目实现时间:

(defn seq1 [s] 
    (lazy-seq 
    (when-let [[x] (seq s)] 
     (cons x (seq1 (rest s)))))) 

(let [start-time (java.lang.System/currentTimeMillis)] 
    (doseq [item (seq1 (gen-lazy-seq 10))] 
    (let [elapsed-time (- (java.lang.System/currentTimeMillis) start-time)] 
     (println "time: " elapsed-time "item: " item)))) 

; output: 
time: 10002 item: 1 
time: 10002 item: 8 
time: 10003 item: 9 
time: 10003 item: 1 
time: 10003 item: 7 
time: 10003 item: 2 
time: 10004 item: 0 
time: 10004 item: 3 
time: 10004 item: 5 
time: 10004 item: 0 

与JohnJ的版本做同样的事GEN-懒-seq的作品如预期

; output: 
time: 1002 item: 4 
time: 2002 item: 1 
time: 3002 item: 6 
time: 4002 item: 8 
time: 5002 item: 8 
time: 6002 item: 4 
time: 7002 item: 5 
time: 8002 item: 6 
time: 9003 item: 1 
time: 10003 item: 4 

编辑2:

这是与它有这个问题产生的不仅序列。地图生成该序列不能被处理步步无论SEQ1包装的:

(defn gen-lazy-seq [size] 
    (map (fn [_] 
     (Thread/sleep 1000) 
     (rand-int 10)) 
     (range 0 size))) 

但是该序列中,也与图创建的工作原理:

(defn gen-lazy-seq [size] 
    (map (fn [_] 
     (Thread/sleep 1000) 
     (rand-int 10)) 
     (repeat size :ignored))) 
+0

我也试过'seq1',并没有设法使它与Clojure 1.5或1.2.1一起工作。这可能是因为你在实现'for'宏时遇到了一些特殊情况,这是一种透明的东西,你不能简单地通过将它封装在你自己的懒惰seq中来关闭它。 – JohnJ

+0

感谢您的测试。这似乎是合理的问题是由于。我试图用地图创建一个lazy-seq,并按预期工作。 – snowape

+0

再测试一下,似乎我和map生成的序列有同样的问题。 – snowape

回答

4

Clojure的懒惰序列通常分块。如果您采用较大的size s,则可以在您的示例中看到分块工作(在此情况下,减少线程休眠时间会有所帮助)。另见these relatedSO posts

虽然for似乎被分块,下面是不是和工作方式所需:

(defn gen-lazy-seq [size] 
    (take size (repeatedly #(do (Thread/sleep 1000) 
           (rand-int 10))))) 

(doseq [item (gen-lazy-seq 10)] 
    (println item)) 

“我进来的在网络上的消息,我希望所有已经接收之前就开始处理它们。 “分块或不分块,如果你懒洋洋地处理它们,实际上应该是这种情况。

相关问题