我想将{a 1, b 2}
clojure.lang.PersistentArrayMap 转换为
[a 1 b 2]
Clojure中的 clojure.lang.PersistentVector 。
我试图用clojure编写一个将{a 1,b 2}转换为[a 1 b 2]的函数。我还写了一个宏,可以给我预期的最终结果。在Clojure中,我们无法将函数内部生成的值传递给宏。为此,我想知道一种可以直接实现宏的方法,该宏可以将{a 1,b 2}转换为(let [a 1 b 2](println a)),该宏将返回1。
(defmacro mymacro [binding & body]
--some implemetation---)
(mymacro '{a 1, b 2} (println a))
1
nil
转换为所需输出的功能。
(defn myfn [x]
(let [a (into (vector) x) b (vec (mapcat vec a))] b))
(myfn '{a 1, b 2})
[a 1 b 2]
(defmacro list-let [bindings & body] `(let ~(vec bindings) ~@body))
(list-let [a 1 b 2] (println a))
1
nil
我想知道如何在宏本身内部实现相同的功能,并避免使用函数实现来获取require输出。与上面给出的虚拟宏相同。我也很想知道是否可以通过任何方式将函数中的值传递给宏,而无需使用 (def)
答案 0 :(得分:3)
通常,宏代码是普通的clojure代码(不同之处在于它返回的clojure代码将在以后进行评估)。因此,您几乎可以想到在clojure中进行编码的任何事情,都可以在宏内部对传递的参数进行处理。
例如,这是您要尝试做的事情(如果我理解正确的话):
(defmacro map-let [binding-map & body]
(let [b-vec (reduce into [] binding-map)]
`(let ~b-vec ~@body)))
(map-let {a 10 b 20}
(println a b)
(+ a b))
;;=> 10 20
30
或类似这样:
(defmacro map-let [binding-map & body]
`(let ~(reduce into [] binding-map) ~@body))
甚至是这样:
(defmacro map-let [binding-map & body]
`(let [~@(apply concat binding-map)] ~@body))
答案 1 :(得分:1)
您不需要为此使用宏,并且在可能的情况下,始终应首选函数而不是宏。
对于您的特殊情况,我有already written a function keyvals
,您可能会觉得很方便:
(keyvals m)
"For any map m, returns the keys & values of m as a vector,
suitable for reconstructing via (apply hash-map (keyvals m))."
(keyvals {:a 1 :b 2})
;=> [:b 2 :a 1]
(apply hash-map (keyvals {:a 1 :b 2}))
;=> {:b 2, :a 1}
如果您对实现感到好奇,这很简单:
(s/defn keyvals :- [s/Any]
"For any map m, returns the (alternating) keys & values of m as a vector, suitable for reconstructing m via
(apply hash-map (keyvals m)). (keyvals {:a 1 :b 2} => [:a 1 :b 2] "
[m :- tsk/Map ]
(reduce into [] (seq m)))