Clojure - 先做 + 懒惰过滤
Clojure - Make first + filter lazy
我正在学习 clojure。在解决其中一个问题时,我不得不使用 first
+ filter
。我注意到过滤器对所有输入都是不必要的 运行ning。
我怎样才能使 filter
懒惰地变为 运行 以便它不需要对整个输入应用谓词。
下面是一个例子,说明它不偷懒,
(defn filter-even
[n]
(println n)
(= (mod n 2) 0))
(first (filter filter-even (range 1 4)))
以上代码打印
1
2
3
而不必超过 2
。我们怎样才能让它变得懒惰?
发生这种情况是因为 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 个元素块在宏伟的计划中 没有 大。
我正在学习 clojure。在解决其中一个问题时,我不得不使用 first
+ filter
。我注意到过滤器对所有输入都是不必要的 运行ning。
我怎样才能使 filter
懒惰地变为 运行 以便它不需要对整个输入应用谓词。
下面是一个例子,说明它不偷懒,
(defn filter-even
[n]
(println n)
(= (mod n 2) 0))
(first (filter filter-even (range 1 4)))
以上代码打印
1
2
3
而不必超过 2
。我们怎样才能让它变得懒惰?
发生这种情况是因为 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 个元素块在宏伟的计划中 没有 大。