Как изменить атомную карту в clojure? - PullRequest
1 голос
/ 25 сентября 2019

Я новичок в clojure, и мне нужно обновить два значения внутри этого атома:

(def app-state (atom {:id "1":status 0 :st 0}))

Я использую следующее:

(let [value (mod (+ (:st @app-state) 1) 4)]
    (swap! app-state update-in [:status] value)
    (swap! app-state update-in [:st] inc))

Я получаю:

Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn

Ответы [ 2 ]

4 голосов
/ 25 сентября 2019

Третий аргумент update-in принимает функцию, но вы предоставляете long (value), поэтому вы получаете исключение.Вместо этого вы можете использовать assoc-in, который принимает значение для непосредственного связывания с картой:

(swap! app-state assoc-in [:status] value)

Однако вы должны выполнить полное обновление состояния атомарно в функции, переданной в swap! например

(swap! app-state (fn [{:keys [st] :as state}]
                    (let [st-next (inc st)
                          value (mod st-next 4)]
                       (merge state {:st st-next
                                     :status value}))))
1 голос
/ 29 сентября 2019

Ниже приведен сеанс repl, основанный на вашей проблеме.Сначала я определяю app-state именно так, как вы отправили.Затем я определяю bump-state как анонимную функцию #(…), которая принимает один аргумент, текущее значение app-state, обозначаемое заполнителем %.Форма let связывает увеличенное значение клавиши :st с st.Наконец, assoc возвращает новую неизменяемую карту, связывая новые значения с :st и :status предыдущей карты.

Следующие несколько строк просто вызывают swap!, чтобы подтвердить, что bump-state работает.Последняя строка просто определяет анонимную функцию непосредственно при вызове swap!.Хотя принятый ответ работает нормально, я думаю, что это немного более кратко.

user=> (def app-state (atom {:id "1":status 0 :st 0}))
#'user/app-state
user=> (def bump-state #(let [st (inc (:st %))] (assoc % :st st :status (mod st 4))))
#'user/bump-state
user=> (swap! app-state bump-state)
{:id "1", :status 1, :st 1}
user=> (swap! app-state bump-state)
{:id "1", :status 2, :st 2}
user=> (swap! app-state bump-state)
{:id "1", :status 3, :st 3}
user=> (swap! app-state bump-state)
{:id "1", :status 0, :st 4}
user=> (swap! app-state #(let [st (inc (:st %))] (assoc % :st st :status (mod st 4))))
{:id "1", :status 1, :st 5}

Вся идея swap! заключается в том, что ваша функция обновления работает с текущим неизменяемым значением, которое хранитсяатомом и возвращает новое неизменное значение, чтобы заменить его.Ваша функция обновления - это просто чистая функция, которая позволяет вам легче рассуждать об этом, а также играть с ней в реплее, как и другие функции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...