Clojure - 让第一个+过滤懒惰

Kan*_*thy 3 clojure lazy-evaluation

我正在学习clojure.在解决其中一个问题时,我不得不使用first+ filter.我注意到过滤器对所有输入都不必要地运行.如何让filter懒惰运行,以便它不需要为整个输入应用谓词.

以下是一个显示它不是懒惰的例子,

(defn filter-even
  [n]
  (println n)
  (= (mod n 2) 0))

(first (filter filter-even (range 1 4)))
Run Code Online (Sandbox Code Playgroud)

上面的代码打印出来

1

2

3

而它不需要超越2.我们怎么能让它变得懒惰?

Car*_*ate 9

range是因为是一个分块序列:

(chunked-seq? (range 1))
=> true
Run Code Online (Sandbox Code Playgroud)

如果可用,它实际上将采用前32个元素:

(first (filter filter-even (range 1 100)))
1
2
. . .
30
31
32
=> 2
Run Code Online (Sandbox Code Playgroud)

此概述显示了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
Run Code Online (Sandbox Code Playgroud)

或者,您可以申请list,因为列表没有分块:

(first (filter filter-even (apply list (range 1 100))))
2
=> 2
Run Code Online (Sandbox Code Playgroud)

但显然,整个系列需要实现预过滤.

老实说,这并不是我曾经过于关注的事情.过滤功能通常不是昂贵,并且在宏观方案中32个元素块并不是那么大.