Яка різниця між дозою і в Клоджуре? Наведіть кілька прикладів, коли ви вирішили використовувати один над іншим?
Яка різниця між дозою і в Клоджуре? Наведіть кілька прикладів, коли ви вирішили використовувати один над іншим?
Відповіді:
Різниця полягає в тому, що for
будується лінива послідовність і повертає її, а doseq
для виконання побічних ефектів і повертає нуль.
user=> (for [x [1 2 3]] (+ x 5))
(6 7 8)
user=> (doseq [x [1 2 3]] (+ x 5))
nil
user=> (doseq [x [1 2 3]] (println x))
1
2
3
nil
Якщо ви хочете побудувати нову послідовність на основі інших послідовностей, використовуйте для. Якщо ви хочете зробити побічні ефекти (друк, запис у базу даних, запуск ядерної боєголовки тощо) на основі елементів з деяких послідовностей, використовуйте doseq.
Зауважте також, що doseq
прагне, поки for
ледачий. Приклад відсутній у відповіді Рейна:
(for [x [1 2 3]] (println x))
У системі REPL це, як правило, робити те, що ви хочете, але це, в основному, збіг обставин: REPL змушує ліниву послідовність, що створюється for
, викликаючи printlns. У неінтерактивному середовищі нічого ніколи не буде надруковано. Ви можете бачити це в дії, порівнюючи результати
user> (def lazy (for [x [1 2 3]] (println 'lazy x)))
#'user/lazy
user> (def eager (doseq [x [1 2 3]] (println 'eager x)))
eager 1
eager 2
eager 3
#'user/eager
Оскільки def
форма повертає створений новий var, а не пов'язане з ним значення, REPL нічого не надрукує, і lazy
буде посилатися на нереалізований lazy-seq: жоден з його елементів взагалі не був обчислений. eager
буде посилатися nil
, і вся його друк буде зроблена.