我最近一直在写一些Clojure,我发现自己经常使用以下模式:
(let [x (bam)
y (boom)]
{:x x
:y y})
所以我继续写下面的宏:
(defmacro make-keyword-map [& syms]
`(hash-map ~@(mapcat (fn [s] [(keyword (name s)) s]) syms)))
有了这个,代码现在看起来像:
(let [x (bam)
y (boom)]
(make-keyword-map x y)
这种宏会被视为惯用吗?或者我做错了什么,并且缺少一些已经建立的模式来处理这类事情?
答案 0 :(得分:7)
注意,您也可以替换所有:
(let [x (bam)
y (boom)]
{:x x
:y y})
只是:
{:x (bam)
:y (boom)}
将评估同样的事情。
如果你的let
表达式彼此依赖,那么宏如何如此:
(defmacro make-keyword-map [& let-body]
(let [keywords-vals (flatten (map (juxt keyword identity)
(map first (partition 2 let-body))))]
`(let ~(vec let-body)
(hash-map ~@keywords-vals))))
那样(make-keyword-map x (foo 1) y (bar 2) z (zoom x))
扩展为:
(clojure.core/let [x (foo 1) y (bar 2) z (zoom x)]
(clojure.core/hash-map :x x :y y :z z))
所以这样的事情会起作用:
user=> (defn foo [x] (+ x 1))
#'user/foo
user=> (defn bar [x] (* x 2))
#'user/bar
user=> (defn zoom [x] [(* x 100) "zoom!"])
#'user/zoom
user=> (make-keyword-map x (foo 1) y (bar 2) z (zoom x))
{:z [200 "zoom!"], :y 4, :x 2}
不确定这是多么惯用,但与原始示例相比,它还为您节省了let
。