简体   繁体   English

在定义的函数中包装Clojure Atom不会更新

[英]Clojure Atom Doesn't Update When Wrapped in Defined Function

Not sure what is going on here, but I have this code, where the map function successfully executes in my repl without being wrapped in a 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})}

Yet, when I define the map function as such: 但是,当我这样定义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)

I get the following result: 我得到以下结果:

=> {:above-four (), :below-four ()}

I'm very confused, because this function taken straight from the Clojure docs works just fine: 我很困惑,因为直接从Clojure文档中获取的此功能可以正常工作:

(def m1 (atom {:a "A" :b "B"}))

(defn update-m1 []
    (swap! m1 assoc :a "Aaay")
    @m1)

=> {:a "Aaay", :b "B"}

Because test-dogs uses map , it returns a lazy sequence . 由于test-dogs使用map ,因此它返回一个惰性序列 The elements of lazy sequences aren't realized until they're needed. 直到需要时才意识到惰性序列的元素。

The problem with your set up is you're trying to use map to run a side effect (the call to swap! ; an impure action), and never actually use the result of map . 设置的问题是,您试图使用map产生副作用(调用swap! ;不纯净的动作),而从不实际使用map的结果。 Because you never request results from map , the mapping function containing swap! 因为您永远不会从map请求结果,所以包含swap!的映射函数swap! never runs. 永远不会运行。

By using mapv (which returns a non-lazy vector), or doseq (which is meant to carry out side effects): 通过使用mapv (返回一个非惰性向量)或doseq (它会产生副作用):

(doseq [dog dogs]
  (let [k (if (> (:age dog) 4)
                :above-four
                :below-four)]

     (swap! ages update k merge dog))) 

You can force the side effects to run. 您可以强制副作用运行。

I cleaned up the code a bit. 我整理了一下代码。 The -in versions you were using were unnecessary; 您使用的-in版本是不必要的; as was the the call to get-in . 就像get-in的调用一样。 I also got rid of the redundant calls to swap! 我也摆脱了多余的swap!电话swap! .

Note though that at least in your example, use of atom s is entirely unnecessary. 请注意,尽管至少在您的示例中,完全不需要使用atom Even if you have a more complicated use case, make sure their use is justified. 即使您有更复杂的用例,也请确保合理使用它们。 Mutable variables just aren't as common in languages like Clojure. 可变变量在Clojure之类的语言中并不常见。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM