Как найти длину ленивой последовательности без реализации форсирования?

В настоящее время я читаю книгу по программированию O'reilly Clojure, в которой в разделе о ленивых последовательностях говорится:

Возможно (хотя и очень редко) ленивая последовательность знает свою длину и, следовательно, возвращает ее в результате подсчета, не осознавая ее содержимого.

У меня вопрос: как это делается и почему это так редко?

К сожалению, в книге об этом не говорится в этом разделе. Я лично считаю, что очень полезно знать длину ленивой последовательности до ее реализации, например, на той же странице приведен пример ленивой последовательности файлов, которые обрабатываются функцией с использованием map. Было бы неплохо знать, сколько файлов можно обработать, прежде чем реализовывать последовательность.


person izaban    schedule 27.08.2013    source источник


Ответы (2)


Полагаю, это связано с тем, что обычно есть другие способы узнать размер.

Единственная реализация последовательности, о которой я могу думать сейчас, которая потенциально могла бы это сделать, - это своего рода карта дорогостоящей функции / процедуры над коллекцией известного размера.

Простая реализация вернула бы размер базовой коллекции, откладывая реализацию элементов ленивой последовательности (и, следовательно, выполнение дорогостоящей части) до тех пор, пока она не понадобится.

В этом случае вы заранее знаете размер отображаемой коллекции и можете использовать его вместо размера lazy-seq.

Иногда это может быть удобно, и поэтому его можно реализовать, но я думаю, что редко бывает необходимо.

person soulcheck    schedule 27.08.2013
comment
Очевидно, это не единственный возможный пример. А что насчет (repeat 1000 x)? (range 100)? Есть много видов ленивых последовательностей, которые могут знать свою длину, но не запрограммированы просто потому, что это потребует времени разработки и накладных расходов времени выполнения, что, вероятно, является небольшим преимуществом. - person amalloy; 28.08.2013
comment
@amalloy, поэтому я сказал, что могу придумать, может быть, мне следовало добавить сейчас в конце :) Тем не менее, остальная часть ответа остается в силе - длина ленивой последовательности известна до ее создания, поэтому нет реального преимущества от умной реализации длина в самой последовательности. - person soulcheck; 28.08.2013
comment
Означает ли это, что невозможно подсчитать без осознания ленивой последовательности, являющейся результатом filter? Произнесите ленивую последовательность из нескольких миллионов случайных чисел: (->> my-rand-int-lazy-seq (filter #(even? %)) (count-without-realization))? - person adamneilson; 29.09.2015

Вдохновленный ответом soulcheck, вот ленивая, но рассчитанная карта дорогостоящей функции для коллекции фиксированного размера.

(defn foo [s f] 
  (let [c (count s), res (map f s)] 
    (reify 
      clojure.lang.ISeq 
        (seq [_] res) 
      clojure.lang.Counted 
        (count [_] c) 
      clojure.lang.IPending 
        (isRealized [_] (realized? res)))))


(def bar (foo (range 5) (fn [x] (Thread/sleep 1000) (inc x))))

(time (count bar))
;=> "Elapsed time: 0.016848 msecs"
;    5

(realized? bar)
;=> false


(time (into [] bar))
;=> "Elapsed time: 4996.398302 msecs"
;   [1 2 3 4 5]

(realized? bar)
;=> true

(time (into [] bar))
;=> "Elapsed time: 0.042735 msecs"
;   [1 2 3 4 5]
person A. Webb    schedule 27.08.2013