2013-08-27 7 views
7

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

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

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

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

ответ

7

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

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

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

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

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

+1

Это, очевидно, не единственный возможный пример. Что относительно '(repeat 1000 x)'? '(диапазон 100)'? Существует много видов ленивых последовательностей, которые * могут * знать их длину, но не имеют его запрограммированного просто потому, что это потребует инженерного времени и имеет накладные расходы на время, вероятно, небольшое преимущество. – amalloy

+0

@amalloy вот почему я сказал «я могу думать», может быть, я должен был добавить «сейчас» в конце :) Еще остальная часть ответа - длина ленивой последовательности известна до ее создания, поэтому нет реальный выигрыш в умном внедрении длины в самой последовательности. – soulcheck

+0

Означает ли это, что невозможно рассчитывать без реализации ленивой последовательности, которая является результатом «фильтра»? Скажем, ленивый seq из нескольких миллионов случайных чисел: '(- >> my-rand-int-lazy-seq (фильтр # (даже?%)) (Count-without-implementation))'? – adamneilson

9

Как вдохновлено soulcheck's answer, здесь представлена ​​ленивая, но подсчитанная карта дорогой функции по коллекции фиксированного размера.

(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] 
+0

+1 для примера реализации – soulcheck

 Смежные вопросы

  • Нет связанных вопросов^_^