2013-06-26 39 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)) 

「我進來的在網絡上的消息,我希望所有已經接收之前就開始處理它們。 「分塊或不分塊,如果你懶洋洋地處理它們,實際上應該是這種情況。

相關問題