Assume the following,
(in-ns silly.fun)
(def a 1)
(defn fx [b]
((fn [c] (return-all-symbols)) (first b)))
I was wondering if it is possible to have a return-all-symbols function that would return the map of symbols/values currently scoped at its invocation. So, assuming the above was compiled and we were in the 'silly.fun namespace, we could run something like the following.
(fx [:hello]) => {"a" 1, "b" [:hello], "c" :hello}
I would like to use return-all-symbols for debugging purposes. Is return-all-symbols at all possible? If so, what is its implementation?
It's possible, but as you've defined it you'd be pretty sad: you don't want a map with hundreds of entries referring to all the functions in clojure.core! And even if you only look in the current namespace, you forgot to include fx
, which is a symbol whose value is a function. Plus there will often be lexical symbols you don't want, introduced by macros. eg, (let [[x y] foo])
would show four symbols available: foo, x, y, and something like vec__auto__4863
.
Anyway, you probably have to live with some compromise over those issues, or else (and really I think this is better) specify which symbols you actually want a map of. But to automatically get values for those symbols which are either (a) lexical or (b) defined in the current namespace, and also (c) not mapping to a function, you could use:
(defmacro return-all-symbols []
(let [globals (remove (comp :macro meta val) (ns-publics *ns*))
syms (mapcat keys [globals, &env])
entries (for [sym syms]
[`(quote ~sym) sym])]
`(into {}
(for [[sym# value#] [~@entries]
:when (not (fn? value#))]
[sym# value#]))))
(def a 1)
(defn fx [b]
((fn [c] (return-all-symbols)) (first b)))
(fx [:hello])
;=> {a 1, c :hello, b [:hello]}
Namespaces contain a map with all the currently scoped vars, which gives you part of what you want. It would miss lexicaly scoped symbols from expressions like (let [x 4] (return-all-symbols))
though may still be useful for debugging:
core> (take 2 (ns-map *ns*))
([sorted-map #'clojure.core/sorted-map] [read-line #'clojure.core/read-line])
if you need more than this then you may need a real debugger that uses the java debugging interface. check out the clojure debugging toolkit
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