Clojure中的make-keyword-map - 惯用语?

mis*_*tor 5 lisp idiomatic clojure

我最近一直在写一些Clojure,我发现自己经常使用以下模式:

(let [x (bam)
      y (boom)]
  {:x x
   :y y})
Run Code Online (Sandbox Code Playgroud)

所以我继续写下面的宏:

(defmacro make-keyword-map [& syms]
  `(hash-map ~@(mapcat (fn [s] [(keyword (name s)) s]) syms)))
Run Code Online (Sandbox Code Playgroud)

有了它,代码现在看起来像:

(let [x (bam)
      y (boom)]
  (make-keyword-map x y)
Run Code Online (Sandbox Code Playgroud)

这种宏会被认为是惯用的吗?或者我做错了什么,并且缺少一些已经建立的模式来处理这类事情?

DJG*_*DJG 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))))
Run Code Online (Sandbox Code Playgroud)

那种方式(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))
Run Code Online (Sandbox Code Playgroud)

所以像这样的东西会起作用:

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}
Run Code Online (Sandbox Code Playgroud)

不确定这是多么惯用,但let与原始示例相比,它也可以节省您的费用.

  • 更短的版本:`(defmacro make-keyword-map [&bindings](让[ks(take-nth 2 bindings)] \`(让[〜@ bindings](hash-map~ @)(interleave(map keyword ks) )ks)))))` (2认同)