Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Clojure中,懒惰的seq总是分块吗?_Clojure_Lazy Evaluation_Chunking_Lazy Sequences - Fatal编程技术网

在Clojure中,懒惰的seq总是分块吗?

在Clojure中,懒惰的seq总是分块吗?,clojure,lazy-evaluation,chunking,lazy-sequences,Clojure,Lazy Evaluation,Chunking,Lazy Sequences,我的印象是懒惰的seq总是被分块 => (take 1 (map #(do (print \.) %) (range))) (................................0) 正如预期的那样,打印32个点,因为range返回的惰性seq被分为32个元素块。但是,当我用自己的函数获取rss提要代替范围尝试此操作时,惰性seq不再分块: => (take 1 (map #(do (print \.) %) (get-rss-feeds r))) (."http://

我的印象是懒惰的seq总是被分块

=> (take 1 (map #(do (print \.) %) (range)))
(................................0)
正如预期的那样,打印32个点,因为
range
返回的惰性seq被分为32个元素块。但是,当我用自己的函数
获取rss提要
代替
范围
尝试此操作时,惰性seq不再分块:

=> (take 1 (map #(do (print \.) %) (get-rss-feeds r)))
(."http://wholehealthsource.blogspot.com/feeds/posts/default")
只打印了一个点,所以我猜
getrssfeeds
返回的惰性seq没有分块。事实上:

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

=> (chunked-seq? (seq (get-rss-feeds r)))
false
以下是获取rss提要的源代码:

(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])))
因此,看起来块度取决于懒惰seq的生成方式。我查看了函数
范围
的源代码,有迹象表明它是以一种“粗块”的方式实现的。所以我有点搞不清楚这是怎么回事。有人能澄清一下吗


这就是我需要知道的原因

我必须执行以下代码:
(获取rss条目(获取rss提要h-res)url)

调用
getrssfeeds
返回我需要检查的提要的一个惰性url序列

调用
get rss entry
查找特定条目(其:link字段与get rss entry的第二个参数匹配)。它检查
getrssfeeds
返回的惰性序列。评估每个项目需要通过网络发出http请求以获取新的rss提要。为了尽量减少http请求的数量,必须逐个检查序列,并在匹配时立即停止

代码如下:

(defn get-rss-entry
  [feeds url]
  (ffirst (drop-while empty? (map #(entry-with-url % url) feeds))))
带有url的条目
返回延迟的匹配序列,如果没有匹配,则返回空序列

我对此进行了测试,它似乎工作正常(一次评估一个提要url)。但我担心的是,在某个地方,不知何故,它会开始以一种“笨重”的方式运行,并开始一次评估32个提要。我知道有办法,但在这种情况下似乎根本不需要


我是否非惯用地使用lazy seq?循环/重复是一个更好的选择吗?

依赖于组块的模糊性似乎是不明智的,正如你上面提到的。在您确实需要不分块的情况下,显式地“取消分块”也是明智的,因为如果在某个其他点您的代码以分块化的方式更改,那么事情就不会中断。另一方面,如果您需要按顺序执行操作,代理是一个很好的工具,您可以将下载功能发送给代理,然后无论您如何评估该功能,它们都将一次运行一个,并且只运行一次。在某些情况下,您可能希望
pmap
您的序列,然后即使取消分块也无法工作,尽管使用atom仍能正常工作

惰性序列并不总是分块的,这取决于它们是如何产生的

例如,此函数生成的惰性seq不分块:

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

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

但许多其他clojure内置函数确实会出于性能原因(例如)生成分块的seq,您的担心是对的。如果
feeds
参数是一个返回分块seq的集合,那么您的
getrss条目
确实会调用带有url的
条目
。例如,如果
feeds
是一个向量,
map
将一次对整个块进行操作

Fogus的《Clojure之乐》直接解决了这个问题,第12章定义了功能
seq1

(defn seq1 [s]
  (lazy-seq
    (when-let [[x] (seq s)]
      (cons x (seq1 (rest s)))))) 
您可以在您知道您想要尽可能多的惰性的地方使用此选项,就在您使用url调用
条目之前:

(defn get-rss-entry [feeds url] (ffirst (drop-while empty? (map #(entry-with-url % url) (seq1 feeds))))) (defn获取rss条目 [订阅源url] (ffirst(空时删除)(映射#(url为%url的条目)(seq1提要')))
如果您使用
clojure.core
中的各种块函数和/或您的序列实现
IChunk
IChunkedSeq
接口,则序列似乎仅被“分块”。目前(在1.4.0中),这些都没有文档记录。您使用的是clojure的哪个版本?能否请您用示例代码的草图对此进行扩展?你是说代理而不是原子吗?你是说代理而不是原子吗?因为提供了交换功能!将重试/atom/agent/g对此表示抱歉。我的手指背叛了我的大脑,按错了键。。。修好了,非常感谢。顺便说一句,我刚看完这本书,把我的Clojure游戏带到了一个新的高度。迫不及待地等待更新版本。值得指出的是,对
seq1
的调用必须在源代码处完成。例如,如果您在一个分块序列上接收到来自
map
的延迟序列,那么您就不走运了-
map
无论您做什么都会向前看。添加
map
filter
都可能产生分块序列,这一点非常重要。将副作用和懒惰混为一谈会产生微妙的错误。我来帮忙。