2012-09-13 5 views
14

私は、怠惰なseqsが常にチャンクされているという印象を受けました。Clojureでは、怠惰なseqsは常にチャンクされていますか?

=> (take 1 (map #(do (print \.) %) (range))) 
(................................0) 

rangeによって返さ怠惰配列は32の素子チャンクにチャンクされているため、期待32個のドットが印刷されるように。

=> (take 1 (map #(do (print \.) %) (get-rss-feeds r))) 
(."http://wholehealthsource.blogspot.com/feeds/posts/default") 

一つだけのドットが印刷されるので、私はget-rss-feedsによって返さ怠惰-seqのがチャンクされていないと思います。代わりにrangeの私は私自身の機能get-rss-feedsでこれをしようとすると、しかし、怠惰な配列はもはやチャンクされません。実際:ここ

=> (chunked-seq? (seq (range))) 
true 

=> (chunked-seq? (seq (get-rss-feeds r))) 
false 

get-rss-feedsのソースです:

(defn get-rss-feeds 
    "returns a lazy seq of urls of all feeds; takes an html-resource from the enlive library" 
    [hr] 
    (map #(:href (:attrs %)) 
     (filter #(rss-feed? (:type (:attrs %))) (html/select hr [:link]))) 

だから、chunkinessは怠惰な配列が生成される方法に依存していることが表示されます。私は関数rangeのソースを覗き込んでいて、それが「かっこいい」方法で実装されているというヒントがあります。だから私はこのことがどのように動作するかについて少し混乱している。誰かが明確にしてもらえますか?


私が知る必要があるのはここです。

私は、次のコードを持っている:(get-rss-entry (get-rss-feeds h-res) url)

get-rss-feedsへの呼び出しは、私が検討する必要があるフィードのURLの怠惰なシーケンスを返します。

get-rss-entryを呼び出すと、特定のエントリ(:linkフィールドがget-rss-entryの2番目の引数と一致する)が検索されます。 get-rss-feedsによって返される遅延シーケンスを調べます。各アイテムを評価するには、ネットワーク経由で新しいRSSフィードを取得するためのHTTPリクエストが必要です。 HTTPリクエストの数を最小限に抑えるには、シーケンスを1つずつ調べて、一致するとすぐに停止することが重要です。ここ

コードである:

(defn get-rss-entry 
    [feeds url] 
    (ffirst (drop-while empty? (map #(entry-with-url % url) feeds)))) 

entry-with-url一致がない場合マッチの遅延シーケンスまたは空のシーケンスを返します。

これをテストしたところ、正しく動作しているようです(一度に1つのフィードURLを評価する)。しかし、私はどこかで、どうにかして "かすかな"やり方で行動し始め、一度に32のフィードを評価し始めると心配しています。私はavoid chunky behavior as discussed hereへの道があることを知っていますが、この場合でも必要ないようです。

私は怠惰なseqを非イディオムで使っていますか?ループ/再発はより良い選択肢になりますか?

+0

順序が唯一の「チャンク」あなたは 'clojure.core'および/またはあなたの順序で様々なチャンク機能を使用する場合は、' IChunk'を実装していることが表示されます'IChunkedSeq'インターフェース。現在(1.4.0)、これらは文書化されていません。 – noahlz

+0

あなたはどのバージョンのclojureを使用していますか? –

+0

私はClojure v1.4を使用しています –

答えて

3

あなたが上記のように勘違いの曖昧さに応じて。あなたが実際にチャンクされていないことを明示的に「un chunking」することは賢明です。別のノートでは、アクションが連続している必要がある場合、エージェントは素晴らしいツールですエージェントにダウンロード機能を送ることができました。その後、機能の評価方法に関係なく、一度に1回だけ実行されます。ある時点で、pmapのシーケンスが必要な場合があります。アトムを使用しても正常に動作しますが、un-chunkingさえ機能しません。

+2

サンプルコードのスケッチでこれを拡張してください。あなたは原子の代わりにエージェントを意味しますか? – noahlz

+0

ここでは原子ではなくエージェントを意味しますか?スワップ機能が提供されているからです!再試行されます – noisesmith

+0

s/atom/agent/gそれは残念です。私の指が私の脳を裏切り、間違ったキーを押した...固定された。 –

5

遅延ステージはであるとは限りません。 - 生成方法によって異なります。

は、たとえば、この機能によって生成怠惰な配列がチャンクされていません。

(defn integers-from [n] 
    (lazy-seq (cons n (do (print \.) (integers-from (inc n)))))) 

(take 3 (integers-from 3)) 
=> (..3 .4 5) 

しかし、他の多くのClojureの組み込み関数が

+1

'map'と' filter'の両方がチャンクされたseqを生成するかもしれないということを追加することは非常に重要です。副作用と怠惰を混ぜることは微妙なバグのレシピです。トランスデューサはここで助けます。 –

11

あなたは、パフォーマンス上の理由から、チャンクseqs(例えばrange)を産生行います心配する権利。 feedsパラメータがチャンクされたseqを返すコレクションの場合は、get-rss-entryは実際にはentry-with-urlを厳密に必要以上に呼び出します。たとえば、feedsがベクトルの場合、mapは一度に全チャンクで動作します。

この問題は、第12章で定義された関数seq1で、ClojureののFogus' 喜びに直接対処される:

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

あなたは右、あなたは可能な限り最も怠惰をしたい知っているこの権利を使用することができますあなたがentry-with-urlを呼び出す前に:

 
(defn get-rss-entry 
    [feeds url] 
    (ffirst (drop-while empty? (map #(entry-with-url % url) (seq1 feeds))))) 
+0

ありがとうございました。 BTWちょうど本を終え、私のClojureゲームを次のレベルに引き上げました。更新されたバージョンを待つことはできません。 –

+0

'seq1'へのこの非チャンクコールは、source_で行わなければならないことを指摘する価値があります。あなたがチャンクシーケンスの上で 'map'からレイジーシーケンスを受け取っているならば、あなたは運が悪いです - ' map'はあなたが何をしても先を見越します。 – Thom

関連する問題