Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure get local lets

Tags:

clojure

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.

like image 435
Kevin Kostlan Avatar asked Aug 18 '15 13:08

Kevin Kostlan


1 Answers

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}
like image 125
Alex Avatar answered Oct 29 '22 11:10

Alex