Як перетворити ліниву послідовність на неліниву в Clojure


95

Я спробував наступне в Clojure, очікуючи повернення класу не ледачої послідовності:

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

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

Отже, які ідіоматичні засоби створення нелінивої послідовності з лінивої?


Я здивований, що ніхто не запитував, чому ви стурбовані фактичним типом поверненої вартостіdoall
tar

Ви можете перетворити на вектор:(vec (take 3 (repeatedly rand)))
Кріс,

Відповіді:


161

doallце все, що вам потрібно. Те, що seqтип has LazySeqне означає, що він очікує оцінки. Ледачі seqкешують їх результати, тому все, що вам потрібно зробити, - це пройтися лінивим seqодин раз (як doallце робиться) для того, щоб змусити все це і тим самим зробити його не лінивим. seqце НЕ змусить всю колекцію , щоб оцінити.


2
Я змінив це на прийняту відповідь. Що стосується примітки, за допомогою яких засобів ви можете визначити, чи раніше оцінювали LazySeq?
Тім Клемонс

10
Я вірю, що ти просто дзвониш realized?.
too farsideways

1
Напевно, повинна бути realizeоперація, яка відповідає realized?.
Reut Sharabani

Це все дуже приємно. Але оскільки деяким функціям, на зразок contains?, байдуже, зрозумів ти ледачий слід чи ні, це відповідає на конкретне запитання, як його задали, але менше на назву запитання.
matanster

75

Це до певної міри питання таксономії. лінива послідовність - це лише один тип послідовності, як і список, вектор або карта. Отже, відповідь, звичайно, "це залежить від того, який тип не ледачої послідовності ви хочете отримати:
Виберіть свій вибір із:

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

Ви можете мати будь-який тип послідовності, що найбільше відповідає вашим потребам.


Це найкраща відповідь.
Феліпе

4
Прийнята відповідь технічно правильна, але ця відповідь мені була найкориснішою. Я намагався відобразити функцію над вектором, а потім виплюнув результати у файл, і навіть після виклику doall файл замість вмісту послідовності містив "clojure.lang.LazySeq@address". Виклик vec на мапі значень повернув мені те, що мені потрібно було виплюнути у файл.
Джессі Розалія

1
@JesseRosalia Приємно знати, що одна й та сама відповідь Rich Hickey у всіх SO була технічно правильною. ;-)
Філ Купер

(vec (my-lazy-seq))не настільки приємно в таких ситуаціях, як наступна: (vec (json/parse-string "{\"foo\":\"bar\"}")) ;; => [["foo" "bar"]]Оскільки cheshireвирішує виробляти ледачий- (json/parse-string)
сек

Пом'якшенням вищезгаданого було використання нетерплячих(json/parse-string-strict)
codeasone

22

Цей багатий хлопець, здається, знає свою приналежність і абсолютно має рацію.
Але я думаю, що цей фрагмент коду, використовуючи ваш приклад, може бути корисним доповненням до цього питання:

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

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


2
Однак варто зазначити, що вам не потрібно примусово realized?повертати всю послідовність true. Наприклад(let [r (range) r? (realized? r)] (doall (take 1 r)) [r? (realized? r)]) => [false true]
Алекс Ковентрі

22
Цей багатий хлопець: D ха-ха
німрод

10
@nimrod :) однак каламбур мав бути у "його клоюре".
Петро

10
Для тих, хто не знає, "Багатий хлопець" винайшов Clojure.
erturne

1
@AlexCoventry ваш приклад повертає[true true]

7

Я натрапив на цю публікацію в блозі про те, що doallне є рекурсивним. Для цього я знайшов перший коментар у дописі. Щось на зразок:

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

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


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

3
Це жахлива ідея. Він змінює вхідні послідовності.
amalloy

3
Звичайно, в цьому випадку повернення вводу не має ніякої різниці, оскільки це всього лише 3 випадкові числа .... :-)
mikera
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.