I have been writing some Clojure recently, and I found myself using the following pattern frequently enough:
(let [x (bam)
y (boom)]
{:x x
:y y})
So I went ahead and wrote the following macro:
(defmacro make-keyword-map [& syms]
`(hash-map ~@(mapcat (fn [s] [(keyword (name s)) s]) syms)))
With that, code now looks like:
(let [x (bam)
y (boom)]
(make-keyword-map x y)
Would this sort of macro be considered idiomatic? Or am I doing something wrong, and missing some already established pattern to deal with something of this sort?
Note, that you can also replace all of:
(let [x (bam)
y (boom)]
{:x x
:y y})
with just:
{:x (bam)
:y (boom)}
which will evaluate to the same thing.
If your let
expressions depend on one another, then how about a macro like so:
(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))))
that way (make-keyword-map x (foo 1) y (bar 2) z (zoom x))
expands to:
(clojure.core/let [x (foo 1) y (bar 2) z (zoom x)]
(clojure.core/hash-map :x x :y y :z z))
So something like this would work:
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}
Not sure how idiomatic that is, but it also saves you a let
, compared to your original example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With