我正在学习Clojure。解决其中一个问题时,我不得不使用first
+ filter
。我注意到所有输入的过滤器都不必要地运行。
我该如何使filter
懒惰地运行,以便它不必将谓词应用于整个输入。
下面是一个显示它不是惰性的示例,
(defn filter-even
[n]
(println n)
(= (mod n 2) 0))
(first (filter filter-even (range 1 4)))
上面的代码打印
1
2
3
它不必超出2
。我们如何使它变得懒惰?
答案 0 :(得分:9)
发生这种情况是因为range
是一个分块的序列:
(chunked-seq? (range 1))
=> true
如果有的话,它实际上会占用前32个元素:
(first (filter filter-even (range 1 100)))
1
2
. . .
30
31
32
=> 2
This overview显示了unchunk
函数,可防止这种情况的发生。不幸的是,这不是标准的:
(defn unchunk [s]
(when (seq s)
(lazy-seq
(cons (first s)
(unchunk (next s))))))
(first (filter filter-even (unchunk (range 1 100))))
2
=> 2
或者,由于列表未分块,您可以对其应用list
:
(first (filter filter-even (apply list (range 1 100))))
2
=> 2
但是显然,整个集合需要进行预过滤。
说实话,这不是我一直以来都非常关心的事情。过滤功能通常不会太昂贵,并且32个元素块在事物的宏伟计划中也不是那么大。