Как преобразовать ленивую последовательность в не-ленивый в Clojure

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

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

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

Итак, каково идиоматическое средство создания нелазной последовательности от ленивого?

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

(.getClass (into '() (take 3 (repeatedly rand))))

Ответ 5

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

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

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