【问题标题】:How to use an atom to update a map's state?如何使用原子来更新地图的状态?
【发布时间】:2013-12-27 23:36:36
【问题描述】:

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

期望的行为

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

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

【问题讨论】:

  • 顺便说一句,请查看fnil(fnil inc 0)(fn [old] (inc (or old 0))) 好一点。

标签: clojure


【解决方案1】:

只需要在调用swap!的函数前传递原子即可。

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}
  • 将结果放回原子中。

【讨论】:

    猜你喜欢
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 2022-01-24
    相关资源
    最近更新 更多