我的印象是惰性序列总是被分块的。
=> (take 1 (map #(do (print \.) %) (range)))
(................................0)
正如预期的那样,打印了 32 个点,因为返回的惰性序列range
被分块为 32 个元素块。但是,当range
我不是用自己的函数尝试这个时get-rss-feeds
,惰性序列不再被分块:
=> (take 1 (map #(do (print \.) %) (get-rss-feeds r)))
(."http://wholehealthsource.blogspot.com/feeds/posts/default")
只打印了一个点,所以我猜返回的lazy-seqget-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 个提要。我知道有一种方法可以避免此处讨论的笨拙行为,但在这种情况下似乎甚至不需要。
我是否以非惯用方式使用惰性序列?循环/重复会是更好的选择吗?