Как преобразовать ленивую последовательность в не ленивую - PullRequest
89 голосов
/ 29 октября 2009

Я попробовал следующее в Clojure, ожидая, что будет возвращен класс не ленивой последовательности:

(.getClass (doall (take 3 (repeatedly rand))))

Однако, это все еще возвращает clojure.lang.LazySeq. Я предполагаю, что doall оценивает всю последовательность, но возвращает исходную последовательность, так как она все еще полезна для запоминания.

Так в чем же идиоматическое средство создания не ленивых последовательностей из ленивых?

Ответы [ 5 ]

149 голосов
/ 29 октября 2009

doall - это все, что вам нужно. Тот факт, что seq имеет тип LazySeq, не означает, что он ожидает оценки. Ленивые seqs кэшируют свои результаты, поэтому все, что вам нужно сделать, - это пройти ленивый seq один раз (как это делает doall), чтобы форсировать все это, и, таким образом, сделать его не ленивым. seq не заставляет оценивать всю коллекцию.

63 голосов
/ 29 октября 2009

Это в некоторой степени вопрос таксономии. ленивая последовательность - это просто один тип последовательности , как список, вектор или карта. Поэтому ответ, конечно, «это зависит от того, какой тип последовательности не ленивый вы хотите получить:
Выберите из:

  • ленивая (полностью оцененная) ленивая последовательность (doall ... )
  • список для последовательного доступа (apply list (my-lazy-seq)) OR (into () ...)
  • вектор для последующего произвольного доступа (vec (my-lazy-seq))
  • карта или набор, если у вас есть какое-то специальное назначение.

Вы можете использовать любой тип последовательности, наиболее соответствующий вашим потребностям.

21 голосов
/ 06 сентября 2013

Этот богатый парень, кажется, знает свое заклинание и абсолютно прав.
Но я думаю, что этот фрагмент кода, используя ваш пример, может быть полезным дополнением к этому вопросу:

=> (realized? (take 3 (repeatedly rand))) 
false
=> (realized? (doall (take 3 (repeatedly rand)))) 
true

Действительно тип не изменился, но реализация имеет

7 голосов
/ 29 августа 2015

Я наткнулся на этот блог пост о том, что doall не рекурсивно. Для этого я нашел первый комментарий в посте сделал свое дело. Что-то вроде:

(use 'closure.walk)
(postwalk identity nested-lazy-thing)

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

5 голосов
/ 29 октября 2009
(.getClass (into '() (take 3 (repeatedly rand))))
...