How can you get a map of the local variables defined using let?
(let [foo 1] (println (get (get-thread-bindings) "foo")))
; prints nil
Is there another function that does this? Or is there a way to extract the variables from the get-thread-bindings map? Any solution should work with nested let statements as well.
As pointed out in the link in the comments, there's a special &env variable available inside defmacro. Per the documentation: 
Two special variables are available inside defmacro for more advanced usages:
- &form - the actual form (as data) that is being invoked
 - &env - a map of local bindings at the point of macro expansion. The env map is from symbols to objects holding compiler information about that binding.
 
You can use this to write a macro that will expand to give you a mapping of local bindings at the point where the macro is expanded:
(defmacro get-env
  []
  (into {} (for [k (keys &env)]
             [(name k) k])))
This expands as a map of symbol name (name k) to symbol k for all local bindings (keys &env) which, when evaluated, will give a map of symbol name to current binding for the symbol.
 user> (get-env) ; => {}
 user> (let [a 1] (get-env)) ; => {"a" 1}
 user> (let [a 1 b 2]
         (let [b 3 c 4] (get-env))) ; => {"c" 4, "b" 3, "a" 1}
It even works with function parameters:
 user> (defn foo [x] (let [y 1] (get-env)))
 user> (foo 2) ; => {"y" 1, "x" 2}
                        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