Clojure - 首先+过滤懒惰

标签 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。我们怎样才能让它变懒呢?

最佳答案

发生这种情况是因为 range 是一个分块序列:

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

它实际上会获取前 32 个元素(如果可用):

(first (filter filter-even (range 1 100)))
1
2
. . .
30
31
32
=> 2

This overview显示了一个 uncunk 函数来防止这种情况发生。不幸的是,它不是标准的:

(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 个元素 block 在总体方案中也不会那么大。

关于Clojure - 首先+过滤懒惰,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52332964/

相关文章:

generics - Clojure 相当于 Haskell 的 "Scrap Your Boilerplate"(SYB)

Clojure:以惯用的 Clojure 方式使用 java.util.HashMap

scala - 如何在递归上下文中解释惰性?

clojure - 扩展 clojure core.async 的功能

clojure - 如何从另一个目录运行 lein(没有 cd 到项目目录)?

c# - 为什么 Lazy<T> 在序列化期间强制初始化?

code-generation - 使用Raku计算e数

r - 将变量名传递给 R 中的函数

c# - 我的 Lazy<> 值工厂中的 InvalidOperationException

macros - 强制扩展 Clojure 宏内的表达式