I do a lot of computation in let blocks, returning hash maps containing data. The following is not a very minimal example:
(def ground-truth (let [n 201 t1 2.0 linspace (fn [abn] (let [d (/ (- ba) (dec n))] (map (fn [x] (+ a (* xd))) (range n)))) times (vec (linspace 0.0, t1, n)) wavelength 1 wavespeed 1 f (* (/ wavespeed wavelength) 2 Math/PI) dt (- (get times 1) (get times 0)) amplitude 5.0 ground-level 10.0 h-true (mapv #(+ ground-level (* amplitude (Math/sin (* f %)))) times) h-dot-true (mapv #(* amplitude f (Math/cos (* f %))) times) baro-bias-true -3.777] {:nn, :times times, :ff, :dt dt, :h-true h-true, :h-dot-true h-dot-true, :baro-bias-true baro-bias-true}))
What I want to do is get rid of the repetition in the final expression. This is not such a big problem for this small example, but I have some that are much longer and more complicated, and repetition makes modifying the expression tedious and error prone.
I tried this macro:
(defmacro hashup [name-list] `(into {} (map vector (mapv keyword ~name-list) (mapv eval ~name-list))))
which only works if eval works, which works on vars :
(def foo 41) (def bar 42) (hashup '[foo bar])
{: foo 41 ,: bar 42}
but not on let blocks:
(let [a 1, b (inc a)] (hashup '[ab]))
CompilerException java.lang.RuntimeException: cannot resolve character: a in this context, compilation: (null: 1: 1) Util.java: 221 clojure.lang.Util / runtimeException
core.clj: 3105 clojure.core $ eval / invokeStatic
as expected after addressing the following SO issues, among many others: Variable region + eval in Clojure , eval list in let on Clojure
You could say: "well, you can either repeat your variables outside the borders of your let blocks on def with namespaces, and then use something like hashup , or you can repeat your repetition at the bottom of let blocks and forgets about macromagy. But in this particular use case, there is no “Do not repeat yourself.”
I missed a good way DRY from this type of code?