【发布时间】:2012-09-06 21:10:02
【问题描述】:
我的印象是惰性序列总是被分块的。
=> (take 1 (map #(do (print \.) %) (range)))
(................................0)
正如预期的那样,打印了 32 个点,因为 range 返回的惰性序列被分块为 32 个元素块。但是,当我用自己的函数 get-rss-feeds 代替 range 时,惰性序列不再被分块:
=> (take 1 (map #(do (print \.) %) (get-rss-feeds r)))
(."http://wholehealthsource.blogspot.com/feeds/posts/default")
只打印了一个点,所以我猜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 似乎取决于惰性 seq 的产生方式。我查看了函数range 的源代码,并且有迹象表明它是以“矮胖”的方式实现的。所以我有点困惑这是如何工作的。有人可以澄清一下吗?
这就是我需要知道的原因。
我必须使用以下代码:(get-rss-entry (get-rss-feeds h-res) url)
对get-rss-feeds 的调用会返回我需要检查的提要的惰性URL 序列。
对get-rss-entry 的调用查找特定条目(其 :link 字段与 get-rss-entry 的第二个参数匹配)。它检查get-rss-feeds 返回的惰性序列。评估每个项目需要跨网络的 http 请求来获取新的 rss 提要。为了最大限度地减少 http 请求的数量,重要的是要逐个检查序列并在匹配时立即停止。
代码如下:
(defn get-rss-entry
[feeds url]
(ffirst (drop-while empty? (map #(entry-with-url % url) feeds))))
entry-with-url 返回一个惰性匹配序列,如果没有匹配则返回一个空序列。
我对此进行了测试,它似乎可以正常工作(一次评估一个提要网址)。但我担心在某个地方,它会以某种“笨重”的方式开始表现,并且会开始一次评估 32 个提要。我知道有一种方法可以avoid chunky behavior as discussed here,但在这种情况下似乎甚至不需要它。
我是否在非惯用地使用惰性序列?循环/重复会是更好的选择吗?
【问题讨论】:
-
如果您使用
clojure.core中的各种块函数和/或您的序列实现IChunk和IChunkedSeq接口,则似乎只有“分块”序列。目前(在 1.4.0 中),这些没有记录。 -
你用的是什么版本的clojure?
标签: clojure lazy-evaluation chunking lazy-sequences