Clojure-使第一个+过滤器懒惰

时间:2018-09-14 13:22:21

标签: clojure lazy-evaluation

我正在学习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。我们如何使它变得懒惰?

1 个答案:

答案 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个元素块在事物的宏伟计划中也不是那么大。