使用交换!更新Clojure(脚本)原子中的地图矢量

Jas*_*wis 4 clojure data-structures clojurescript

我有一个原子拿着地图矢量(来自c2库的示例代码):

(def ^:export data
  (atom [{:metric "Revenue", :units "USD in thousands"
           :ranges [150 225 300], :measurements [220 270], :markers [250]}
          {:metric "Profit", :units "%"
           :ranges [20 25 30], :measurements [21 23], :markers [26]}
          {:metric "Order Size", :units "USD average"
           :ranges [350 500 600], :measurements [100 320], :markers [550]}
          {:metric "New Customers", :units "count"
           :ranges [1400 2000 2500],
           :measurements [1000 1650], :markers [2100]}
          {:metric "Satisfaction", :units "out of 5"
           :ranges [3.5 4.25 5], :measurements [3.2 4.7], :markers [4.4]}]))
Run Code Online (Sandbox Code Playgroud)

我可以很容易地修改(好了,创建一个修改后的副本),增加值:markers,因此:

(map (fn [m] (update-in m [:markers] (fn [v]  (map inc v)))) @data)
Run Code Online (Sandbox Code Playgroud)

swap!在大多数情况下,我熟悉更新原子,但在这种情况下我能做的最好的是:

(defn upmark []
  (let [new (map (fn [m] (update-in m [:markers] (fn [v]  (map inc v)))) @data)]
    (vec (reset! data new))))
Run Code Online (Sandbox Code Playgroud)

这显然很糟糕,因为我正在重置原子的整个状态而不是仅仅更新我需要的部分.我只是很困惑为什么在将普通的地图矢量用于执行必需的代码的代码时非常困难swap!.我得到的是swap!隐含的,apply但我似乎无法使应用的fn正确.

ez1*_*1sl 6

你真的很亲密.(swap!)将给定函数应用于atom中的当前值以及传递给swap的任何其他参数.因此,您可以定义一个作用于地图矢量的函数,然后使用(swap!)它将其应用于原子中的值:

(def ^:export data (atom ...))

(defn upmark [data]
    (mapv (fn [m] (update-in m [:markers] (fn [v]  (mapv inc v)))) data))

(swap! data upmark)
Run Code Online (Sandbox Code Playgroud)

请注意,我更改了几个实例(map),(mapv)因此矢量不会变成延迟序列.