我原本认为懒惰序列总是被分块的。
=> (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])))
看起来,分块取决于怎样生成惰性序列。我查看了range
函数的源代码,并且有迹象表明它是以“分块”的方式实现的。所以我有点困惑,希望有人可以澄清一下?
以下是我需要了解的原因。
我有以下代码:
(get-rss-entry (get-rss-feeds h-res) url)
对get-rss-feeds
的调用返回一个URL的惰性序列,我需要检查这个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
返回一个懒惰的匹配序列,如果没有匹配,则返回一个空序列。我测试了一下,对于每个反馈URL逐个评估,它似乎可以正确工作。但我担心有时会变得“卡顿”,并开始同时评估32个反馈。我知道有一种方法可以避免“卡顿”行为,就像这里讨论的那样,但在这种情况下甚至似乎不需要使用它。
我的懒惰序列的使用方式是否符合习惯?使用循环/递归是否更好?
clojure.core
中的各种块函数或者你的序列实现了IChunk
和IChunkedSeq
接口时,序列才会被“分块”。目前(在1.4.0版本中),这些都没有记录。 - noahlz