基于 atom 和 map 函数创造新的价值
Creating new value based on atom and map functions
我想遍历 atom 中的值以创建新集合(但不更新 atom
)。
我有下一个原子定义:
let [st (atom {})]
现在我想这样做:
(-> (seq (keys @st))
(map (fn [key] [key (get @st key)]))))
提供的示例已简化,但即使在这种情况下我也有问题。
我收到下一个错误:
java.lang.IllegalArgumentException: Don't know how to create ISeq from: example.test$init$reify__2273$fn__2275
at clojure.lang.RT.seqFrom(RT.java:505)
at clojure.lang.RT.seq(RT.java:486)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$map$fn__4245.invoke(core.clj:2551)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:484)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$print_sequential.invoke(core_print.clj:46)
at clojure.core$fn__5457.invoke(core_print.clj:147)
at clojure.lang.MultiFn.invoke(MultiFn.java:231)
at clojure.core$pr_on.invoke(core.clj:3392)
at clojure.core$pr.invoke(core.clj:3404)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.core$apply.invoke(core.clj:624)
at clojure.core$print.doInvoke(core.clj:3449)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:624)
at clojure.core$print_str.doInvoke(core.clj:4391)
...
实际上,只使用 @st
就可以了 - 原子的 value 是不可变的。如果您要修改原子,则之前检索到的值不会受到影响(假设您使用的是 Clojure 数据结构)。举例说明:
(def a (atom {:a 1})) ; => #'user/a
(def b @a) ; => #'user/b
(reset! a {:a 2}) ; => {:a 2}
b ; => {:a 1}
"thread first" 宏 (->
) 将前一个表达式返回的值插入到下一个表达式的第二个位置 - 紧接在函数之后。在您的示例中,这会导致 map
函数调用的参数出现错误(函数应该在第一位,集合在第二位)。这就是异常的原因。
在这种情况下,您应该使用 "thread last" 宏 (->>
) 将值插入到下一个函数调用的最后位置:
(let [st (atom {:a 1 :b 2})]
(->> (seq (keys @st))
(map (fn [key] [key (get @st key)]))))
;; returns: ([:b 2] [:a 1])
但是这可以简化为以下内容,因为映射可以直接作为序列遍历,每个元素都是键和值的向量,就像您尝试做的那样:
(let [st (atom {:a 1 :b 2})]
(seq @st))
;; returns: ([:b 2] [:a 1])
如果您希望随时转换这些值,您还可以利用 destructuring,例如调用 map
:
(let [st (atom {:a 1 :b 2})]
(map (fn [[k v]] [k (+ v 1)]) @st))
;; returns: ([:b 3] [:a 2])
因此使用该函数声明为您提取键和值。
我想遍历 atom 中的值以创建新集合(但不更新 atom
)。
我有下一个原子定义:
let [st (atom {})]
现在我想这样做:
(-> (seq (keys @st))
(map (fn [key] [key (get @st key)]))))
提供的示例已简化,但即使在这种情况下我也有问题。 我收到下一个错误:
java.lang.IllegalArgumentException: Don't know how to create ISeq from: example.test$init$reify__2273$fn__2275
at clojure.lang.RT.seqFrom(RT.java:505)
at clojure.lang.RT.seq(RT.java:486)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$map$fn__4245.invoke(core.clj:2551)
at clojure.lang.LazySeq.sval(LazySeq.java:40)
at clojure.lang.LazySeq.seq(LazySeq.java:49)
at clojure.lang.RT.seq(RT.java:484)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$print_sequential.invoke(core_print.clj:46)
at clojure.core$fn__5457.invoke(core_print.clj:147)
at clojure.lang.MultiFn.invoke(MultiFn.java:231)
at clojure.core$pr_on.invoke(core.clj:3392)
at clojure.core$pr.invoke(core.clj:3404)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.core$apply.invoke(core.clj:624)
at clojure.core$print.doInvoke(core.clj:3449)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:624)
at clojure.core$print_str.doInvoke(core.clj:4391)
...
实际上,只使用 @st
就可以了 - 原子的 value 是不可变的。如果您要修改原子,则之前检索到的值不会受到影响(假设您使用的是 Clojure 数据结构)。举例说明:
(def a (atom {:a 1})) ; => #'user/a
(def b @a) ; => #'user/b
(reset! a {:a 2}) ; => {:a 2}
b ; => {:a 1}
"thread first" 宏 (->
) 将前一个表达式返回的值插入到下一个表达式的第二个位置 - 紧接在函数之后。在您的示例中,这会导致 map
函数调用的参数出现错误(函数应该在第一位,集合在第二位)。这就是异常的原因。
在这种情况下,您应该使用 "thread last" 宏 (->>
) 将值插入到下一个函数调用的最后位置:
(let [st (atom {:a 1 :b 2})]
(->> (seq (keys @st))
(map (fn [key] [key (get @st key)]))))
;; returns: ([:b 2] [:a 1])
但是这可以简化为以下内容,因为映射可以直接作为序列遍历,每个元素都是键和值的向量,就像您尝试做的那样:
(let [st (atom {:a 1 :b 2})]
(seq @st))
;; returns: ([:b 2] [:a 1])
如果您希望随时转换这些值,您还可以利用 destructuring,例如调用 map
:
(let [st (atom {:a 1 :b 2})]
(map (fn [[k v]] [k (+ v 1)]) @st))
;; returns: ([:b 3] [:a 2])
因此使用该函数声明为您提取键和值。