Reputation: 18005
I would like to get the name of a variable as a string in Clojure. However, unlike in this question, I would get the name of the original binding (not sure if the terminology is correct, so please see my example below).
(def sample-data1 {:data 1})
(def sample-data2 {:data 2})
(def sample-data3 {:data 3})
(doseq
[my-var [sample-data1 sample-data2 sample-data3]]
(println (name 'my-var)))
In this case, instead of printing
my-var
my-var
my-var
I would like to have :
sample-data1
sample-data2
sample-data3
How do I do that in Clojure ?
Note : This is probably not the prettiest thing to do in a real app. But my question is about if this is this possible.
To clarify : this is for prototyping purposes. In this specific case instead of printing I am filling a (postgres) database with fake data that I write by hand in variables, and I'd like to track where my variable end up without writing too much code.
Upvotes: 0
Views: 510
Reputation: 1261
def
creates a var with the same name as the name of the symbol supplied as def
first parameter. Var in clojure differs from what we usually meant by variable whereas a variable usually can be visualized as a box that contains a value and a var is something that points to a value.
From your example, (here, I am in user
namespace)
user> (def sample-data1 {:data 1})
#'user/sample-data1
clojure creates a #'user/sample-data1
var in user
namespace which points to {:data 1}
value. You can get the value back from that newly create var by deref-ing it using deref
or @
shorthand.
user> (deref #'user/sample-data1)
{:data 1}
user> @#'user/sample-data1
{:data 1}
or if you evaluate a symbol, clojure looks up for a var in the current namespace and returns the value pointed by that var.
user> sample-data1
{:data 1}
you can get a var from a symbol by using var
for #'
shorthand.
user> (var sample-data1)
#'user/sample-data1
user> #'sample-data1
#'user/sample-data1
So, you want the name of the var. The name of the var is contained inside the var's meta data which can be accessed using meta
applied to a var.
user> (meta #'sample-data1)
{:line 1, :column 1, :file "/tmp/form-init3246148490151701909.clj",
:name sample-data1, :ns #object[clojure.lang.Namespace 0x39ba2c26 "user"]}
Above, you can see that the name of the var is located by :name
key.
so, you can get the name of a var from its metadata.
user=> (:name (meta #'sample-data1))
sample-data1
I prefer not to have too many nested parenthesis, so I use thread-first macro ->
user=> (-> #'sample-data1 meta :name)
sample-data1
So back to your question, you need the sample-data[1-3]
vars and their metadata to get their name.
(def sample-data1 {:data 1})
(def sample-data2 {:data 2})
(def sample-data3 {:data 3})
(doseq
[my-var [#'sample-data1 (var sample-data2) #'sample-data3]]
(println (-> my-var meta :name)))
and the result is
sample-data1
sample-data2
sample-data3
nil
Upvotes: 6