Clojure - сделай первым + фильтр ленивый - PullRequest
0 голосов
/ 14 сентября 2018

Я изучаю 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 голосов
/ 14 сентября 2018

Это происходит из-за того, что range представляет собой последовательность фрагментов:

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

И на самом деле она займет первые 32 элемента, если они доступны:

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

Этот обзор показывает функцию 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-элементные блоки не являются такими большими в общей схеме вещей.

...