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返回的值代码>