Как преобразовать ленивую последовательность в не-ленивый в 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
, чтобы вызвать условие ошибки.