【问题标题】:Clojure - Make first + filter lazyClojure - 先做+过滤器懒惰
【发布时间】:2018-09-14 13:22:20
【问题描述】:

我正在学习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。我们怎样才能让它变得懒惰?

【问题讨论】:

  • 您可以考虑使用some 而不是(first (filter ...))

标签: clojure lazy-evaluation


【解决方案1】:

这是因为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 个元素块在总体方案中并没有那么大。

【讨论】:

猜你喜欢
  • 2023-03-18
  • 2010-12-17
  • 1970-01-01
  • 1970-01-01
  • 2018-11-19
  • 1970-01-01
  • 2022-11-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多