Concurrency 具有任意返回值的clojure交换

Concurrency 具有任意返回值的clojure交换,concurrency,clojure,clojurescript,Concurrency,Clojure,Clojurescript,有没有办法交换并返回任意值以及原子的值 例如: (swap! (atom {1 1 2 2 3 3 4 4 5 5}) (fn [m] (loop [] (let [i (rand-int 10)] (if (contains? m i) (recur) (assoc m i "ok")))))) 在上面的函数中,我无法知道哪个键被

有没有办法
交换
并返回任意值以及原子的值

例如:

(swap! (atom {1 1 2 2 3 3 4 4 5 5})
         (fn [m]
           (loop []
             (let [i (rand-int 10)]
               (if (contains? m i)
                 (recur)
                 (assoc m i "ok"))))))
在上面的函数中,我无法知道哪个键被添加到地图中(除非我事先列出它们)


我可以用另一个原子来存储结果,但我忽略了更简单的东西吗?

这里有一个奇怪但通用的方法:

(defn swap-diff! [atom f & args]
  (loop []
    (let [curr-value @atom
          new-value (apply f curr-value args)]
      (if (compare-and-set! atom curr-value new-value)
        [new-value (data/diff curr-value new-value)]
        (recur)))))
这将使用
比较和设置循环中执行code>,直到成功,类似于。成功后,它返回新值的元组和
clojure.data/diff
的输出。
diff
输出将精确显示原子值的变化

(swap-diff! (atom {1 1, 2 2, 3 3})
            #(loop []
               (let [i (rand-int 10)]
                 (if (contains? % i)
                   (recur)
                   (assoc % i "ok")))))
=> [{1 1, 2 2, 3 3, 9 "ok"} (nil {9 "ok"} {3 3, 2 2, 1 1})]
{11,22,33,9“ok”}
是原子的新值
(nil{9“ok”}{3,2,1})
diff
的输出,其中第一项是仅在旧值中的项,第二项是仅在新值中的项,第三项是两者中的项。在您的情况下,您只关心新项目

更新:如果不想处理元组返回值,可以使用diff元数据标记返回值:

(defn swap-diff! [atom f & args]
  (loop []
    (let [curr-value @atom
          new-value (apply f curr-value args)]
      (if (compare-and-set! atom curr-value new-value)
          (with-meta new-value
                     (zipmap [:before :after :both]
                             (data/diff curr-value new-value)))
        (recur)))))
然后对结果调用
meta
,以获得差异:

(meta *1)
=> {:before nil, :after {9 "ok"}, :both {3 3, 2 2, 1 1}}
Clojure 1.9 通过一个新函数
swap vals,这将变得更加干净

(defn swap-diff! [atom f & args]
  (let [[old new] (apply swap-vals! atom f args)]
    (with-meta new (zipmap [:before :after :both]
                           (data/diff old new)))))

这里有一个奇怪但通用的方法:

(defn swap-diff! [atom f & args]
  (loop []
    (let [curr-value @atom
          new-value (apply f curr-value args)]
      (if (compare-and-set! atom curr-value new-value)
        [new-value (data/diff curr-value new-value)]
        (recur)))))
这将使用
比较和设置循环中执行code>,直到成功,类似于。成功后,它返回新值的元组和
clojure.data/diff
的输出。
diff
输出将精确显示原子值的变化

(swap-diff! (atom {1 1, 2 2, 3 3})
            #(loop []
               (let [i (rand-int 10)]
                 (if (contains? % i)
                   (recur)
                   (assoc % i "ok")))))
=> [{1 1, 2 2, 3 3, 9 "ok"} (nil {9 "ok"} {3 3, 2 2, 1 1})]
{11,22,33,9“ok”}
是原子的新值
(nil{9“ok”}{3,2,1})
diff
的输出,其中第一项是仅在旧值中的项,第二项是仅在新值中的项,第三项是两者中的项。在您的情况下,您只关心新项目

更新:如果不想处理元组返回值,可以使用diff元数据标记返回值:

(defn swap-diff! [atom f & args]
  (loop []
    (let [curr-value @atom
          new-value (apply f curr-value args)]
      (if (compare-and-set! atom curr-value new-value)
          (with-meta new-value
                     (zipmap [:before :after :both]
                             (data/diff curr-value new-value)))
        (recur)))))
然后对结果调用
meta
,以获得差异:

(meta *1)
=> {:before nil, :after {9 "ok"}, :both {3 3, 2 2, 1 1}}
Clojure 1.9 通过一个新函数
swap vals,这将变得更加干净

(defn swap-diff! [atom f & args]
  (let [[old new] (apply swap-vals! atom f args)]
    (with-meta new (zipmap [:before :after :both]
                           (data/diff old new)))))

最简单的方法是将返回值和结果都放在映射中:

(swap! (atom {:value {1 1 2 2 3 3 4 4 5 5}
              :return nil})
       (fn [{:keys [value]}]
           (loop []
             (let [i (rand-int 10)]
               (if (contains? value i)
                 (recur)
                 {:value (assoc value i "ok")
                  :return i})))))

请注意,您的示例函数不是纯函数(因为它使用
rand int
),因此它不是
swap的正确用法

最简单的方法是将返回值和结果都放在映射中:

(swap! (atom {:value {1 1 2 2 3 3 4 4 5 5}
              :return nil})
       (fn [{:keys [value]}]
           (loop []
             (let [i (rand-int 10)]
               (if (contains? value i)
                 (recur)
                 {:value (assoc value i "ok")
                  :return i})))))

请注意,您的示例函数不是纯函数(因为它使用
rand int
),因此它不是
swap的正确用法

啊哈,我一直在怀疑关于
rand int
的事情。也许整个问题需要重新思考。但是,不希望改变现有的
atom
的形状。替代方法是通过
with meta
将返回值放入元数据中,或者在let绑定中定义一个易失性框,并将其设置为要使用
vreset返回的值啊哈,我一直在怀疑关于
rand int
的事情。也许整个问题需要重新思考。但是,不希望改变现有的
atom
的形状。替代方法是通过
with meta
将返回值放入元数据中,或者在let绑定中定义一个易失性框,并将其设置为要使用
vreset返回的值