当包装在定义的函数中时,Clojure Atom 不会更新
Clojure Atom Doesn't Update When Wrapped in Defined Function
不确定这里发生了什么,但我有这段代码,其中 map 函数在我的 repl 中成功执行,而没有被包装在定义的函数中:
(def dogs '({:name "scout" :age 5} {:name "rux" :age 3} {:name "fenley" :age 2}))
(def ages (atom {:above-four '() :below-four '()}))
(map
#(if (> (get-in % [:age]) 4)
(swap! ages update-in [:above-four] merge %)
(swap! ages update-in [:below-four] merge %)) dogs)
@ages
=> {:above-four ({:name "scout", :age 5}), :below-four ({:name "fenley", :age 2} {:name "rux", :age 3})}
然而,当我这样定义 map 函数时:
(def ages (atom {:above-four '() :below-four '()}))
(def dogs '({:name "scout" :age 5} {:name "rux" :age 3} {:name "fenley" :age 2}))
(defn test-dogs []
(map
#(if (> (get-in % [:age]) 4)
(swap! ages update-in [:above-four] merge %)
(swap! ages update-in [:below-four] merge %)) dogs)
@ages)
我得到以下结果:
=> {:above-four (), :below-four ()}
我很困惑,因为这个直接取自 Clojure 文档的函数工作得很好:
(def m1 (atom {:a "A" :b "B"}))
(defn update-m1 []
(swap! m1 assoc :a "Aaay")
@m1)
=> {:a "Aaay", :b "B"}
因为 test-dogs
使用 map
,它 returns 一个 惰性序列 。惰性序列的元素只有在需要时才会实现。
你设置的问题是你试图使用 map
来 运行 一个副作用(调用 swap!
;一个不纯的动作),但实际上从来没有使用 map
的结果。因为您从不请求来自 map
的结果,所以包含 swap!
的映射函数从不 运行s.
通过使用 mapv
(returns 非惰性向量)或 doseq
(旨在产生副作用):
(doseq [dog dogs]
(let [k (if (> (:age dog) 4)
:above-four
:below-four)]
(swap! ages update k merge dog)))
您可以将副作用强制为 运行。
我整理了一下代码。您使用的 -in
版本是不必要的;对 get-in
的调用也是如此。我还摆脱了对 swap!
的冗余调用。
请注意,至少在您的示例中,完全没有必要使用 atom
s。即使您有更复杂的用例,也要确保它们的使用是合理的。可变变量在 Clojure 等语言中并不常见。
不确定这里发生了什么,但我有这段代码,其中 map 函数在我的 repl 中成功执行,而没有被包装在定义的函数中:
(def dogs '({:name "scout" :age 5} {:name "rux" :age 3} {:name "fenley" :age 2}))
(def ages (atom {:above-four '() :below-four '()}))
(map
#(if (> (get-in % [:age]) 4)
(swap! ages update-in [:above-four] merge %)
(swap! ages update-in [:below-four] merge %)) dogs)
@ages
=> {:above-four ({:name "scout", :age 5}), :below-four ({:name "fenley", :age 2} {:name "rux", :age 3})}
然而,当我这样定义 map 函数时:
(def ages (atom {:above-four '() :below-four '()}))
(def dogs '({:name "scout" :age 5} {:name "rux" :age 3} {:name "fenley" :age 2}))
(defn test-dogs []
(map
#(if (> (get-in % [:age]) 4)
(swap! ages update-in [:above-four] merge %)
(swap! ages update-in [:below-four] merge %)) dogs)
@ages)
我得到以下结果:
=> {:above-four (), :below-four ()}
我很困惑,因为这个直接取自 Clojure 文档的函数工作得很好:
(def m1 (atom {:a "A" :b "B"}))
(defn update-m1 []
(swap! m1 assoc :a "Aaay")
@m1)
=> {:a "Aaay", :b "B"}
因为 test-dogs
使用 map
,它 returns 一个 惰性序列 。惰性序列的元素只有在需要时才会实现。
你设置的问题是你试图使用 map
来 运行 一个副作用(调用 swap!
;一个不纯的动作),但实际上从来没有使用 map
的结果。因为您从不请求来自 map
的结果,所以包含 swap!
的映射函数从不 运行s.
通过使用 mapv
(returns 非惰性向量)或 doseq
(旨在产生副作用):
(doseq [dog dogs]
(let [k (if (> (:age dog) 4)
:above-four
:below-four)]
(swap! ages update k merge dog)))
您可以将副作用强制为 运行。
我整理了一下代码。您使用的 -in
版本是不必要的;对 get-in
的调用也是如此。我还摆脱了对 swap!
的冗余调用。
请注意,至少在您的示例中,完全没有必要使用 atom
s。即使您有更复杂的用例,也要确保它们的使用是合理的。可变变量在 Clojure 等语言中并不常见。