Я пытался выполнить следующее упражнение из Brave Clojure book:
Создать функцию, которая использует фьючерсы для распараллеливания задачи загрузки случайных цитат из http://www.braveclojure.com/random-quote с использованием (slurp "http://www.braveclojure.com/random-quote"). Фьючерс должен обновить атом, который ссылается на общее количество слов для всех кавычек. Функция примет количество кавычек для загрузки в качестве аргумента и вернет конечное значение атома. Имейте в виду, что вам нужно убедиться, что все фьючерсы завершены, прежде чем возвращать конечное значение атома.
(slurp "http://www.braveclojure.com/random-quote")
Это мое решение:
(def i (atom {})) (defn update-vals [map vals f] (reduce #(update-in % [%2] f) map vals)) (defn incifnil [x] (if (nil? x) 1 (inc x))) (require '[clojure.string :as str]) (defn splitwords [s] (str/split s #"\W")) (defn word-counting [map s] (update-vals map (splitwords s) incifnil)) (defn update-i [s] (swap! i word-counting s)) (defn bring-quote [] (slurp "https://www.braveclojure.com/random-quote")) (defn future-creator [] (future (update-i (bring-quote)))) (defn list_of_futures [n] (map (fn [_] (future-creator)) (range n))) (defn checkall-futures [future-list] (map deref future-list)) (defn quote-word-count [n] (do (checkall-futures (list_of_futures n)) @i))
Но если я попытаюсь взять последнее значение atom i из REPL Я беру пустую карту. Что я делаю не так?
map у вас checkall-futures ленивый. Вам нужно что-то, что заставляет deref на всех предметах. Например, используйте run! вместо map там.
map
checkall-futures
deref
run!
Помимо использования run!, еще одним удобным трюком является использование mapv вместо map везде. mapv всегда дает векторный результат и не ленив. Это устраняет многие проблемы, связанные с ленивостью / синхронизацией при отладке, особенно в REPL.
mapv
Обязательно всегда изучайте Clojure Cheatsheet . Есть также хороший список источников документации , доступных в этом шаблонном проекте .