У меня создалось впечатление, что ленивые последовательности всегда разбиваются на части.
=> (take 1 (map #(do (print \.) %) (range)))
(................................0)
Как и ожидалось, печатаются 32 точки, потому что ленивый seq, возвращаемый range
, разбивается на фрагменты из 32 элементов. Однако, когда вместо range
я пробую это с моей собственной функцией get-rss-feeds
, ленивый seq больше не разбивается на части:
=> (take 1 (map #(do (print \.) %) (get-rss-feeds r)))
(."http://wholehealthsource.blogspot.com/feeds/posts/default")
Печатается только одна точка, поэтому я предполагаю, что lazy-seq, возвращаемый 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-адресов каналов, которые мне нужно изучить.
Вызов 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 канала одновременно. Я знаю, что есть способ избегайте кратковременного поведения, как описано здесь, но в данном случае это даже не требуется.
Я использую lazy seq неидиоматически? Будет ли цикл / повторение лучшим вариантом?
clojure.core
и / или ваша последовательность реализует интерфейсыIChunk
иIChunkedSeq
. В настоящее время (в версии 1.4.0) они недокументированы. - person noahlz   schedule 13.09.2012