如何使用原子来更新地图的状态?

时间:2013-12-27 23:36:37

标签: clojure

我想创建一个函数来保存我认为是垃圾邮件的字符串的频率。我正在尝试使用可以更新的原子地图,因为我给地图一个新的字符串。

所需行为

user> (train-word spam "FREE")
{"FREE": 1}
user> (train-word spam "FREE")
{"FREE" : 2}
user> (train-word spam "MONEY")
{"FREE" : 2 "MONEY" : 1}

到目前为止,我已经尝试了

(def spam (atom {}))
(defn train-word [m word]
  (swap! update-in m [word]
                 (fn [old] (inc (or old 0)))))

但是会产生错误:

clojure.lang.Atom cannot be cast to clojure.lang.Associative  clojure.lang.RT.assoc (RT.java:702)

我是Clojure的新手,所以我在Python中做了一个快速原型

from collections import defaultdict
spam = defaultdict(int)
def train_word(word, spam):
        spam[word] += 1

使用原子管理状态以更新当前值以及添加新值的惯用方法是什么?谢谢!

1 个答案:

答案 0 :(得分:8)

只需要在调用swap!的函数之前传递atom。

user> (def spam (atom {}))                                                        
#'user/spam 
user> (defn train-word [m word]  
        (swap! m update-in [word]  
               (fn [old] (inc (or old 0)))))                                      
#'user/train-word 
 user> (train-word spam "FREE")                                                    
{"FREE" 1}

swap!通过以下方式构造函数调用:

  • 在第一个参数之后列出所有内容的列表,
    (update-in [word] (fn [old] (inc (or old 0)))
  • 获取原子当前第一个参数的值,
    @m
  • 将该值作为此列表中的第二项插入(在函数名称后面)
    (update-in @m [word] (fn [old] (inc (or old 0)))
  • 评估此列表:
    {"FREE" 1}
  • 将结果放回原子中。