In Clojure, how to define a variable named by a string?

Clojure's "intern" function is for this purpose.

Clojure's "intern" function is for this purpose: (doseq x "a" "b" "c" (intern *ns* (symbol x) 666)).

Answer. I've given you the tickmark and hope sepp2k isn't mad about losing it. Thanks!

– Carl Smotricz Mar 28 '10 at 8:22.

(doall (for x "a" "b" "c" (eval `(def ~(symbol x) 666)))) In response to your comment: There are no macros involved here. Eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.

` means the contents of the following lists shall be quoted unless preceded by a ~ ~ the following list is a function call that shall be executed, not quoted. So `(def ~(symbol x) 666) is the list containing the symbol def, followed by the result of executing symbol x followed by the number of the beast. I could as well have written (eval (list 'def (symbol x) 666)) to achieve the same effect.

I knew this answer involved eval somehow but forgot about the ~ construct. – JUST MY correct OPINION Mar 21 '10 at 12:09 Well, whaddaya know, it just works! I hadn't thought it'd be necessary to drop to the macro level to accomplish this, but I'm happy to include this in my "cookbook for stuff I don't fully understand".

Thank you! – Carl Smotricz Mar 21 '10 at 12:41 2 @CarlSmotricz: I just added some explanations to the code. Hopefully you understand more fully now.

– sepp2k Mar 21 '10 at 12:53 Aha! I'd previously seen the tilde ( ~ ) in a macro context. Thanks some more!

– Carl Smotricz Mar 21 '10 at 14:14 1 Please! Don't use eval! Use intern!

But beware of redefining existing Vars! – kotarak Mar 21 '107 at 10:50.

Updated to take Stuart Sierra's comment (mentioning clojure. Core/intern) into account. Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already.In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.

If the Var is known to exist: (alter-var-root (resolve (symbol "foo")) (constantly new-value)) So you could do (dorun (map #(-> %1 symbol resolve (alter-var-root %2)) "x" "y" "z" value-for-x value-for-y value-for z)) (If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function. ) If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it): (defn create-var ;; I used clojure.lang. Var/intern in the original answer, ;; but as Stuart Sierra has pointed out in a comment, ;; a Clojure built-in is available to accomplish the same ;; thing (sym (intern *ns* sym)) (sym val (intern *ns* sym val))) Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case.

With this, you can solve the original problem like so: (dorun (map #(create-var (symbol %) 666) "x" "y" "z")) Some additional examples: user> (create-var 'bar (fn _ :bar)) #'user/bar user> (bar :foo) :bar user> (create-var 'baz) #'user/baz user> baz ; Evaluation aborted. ; java.lang. IllegalStateException: ; Var user/baz is unbound.

; It does exist, though! ;; if you really wanted to do things like this, you'd ;; actually use the clojure.contrib. With-ns/with-ns macro user> (binding *ns* (the-ns 'quux) (create-var 'foobar 5)) #'quux/foobar user> quux/foobar 5.

Very cool and very informative, thanks a lot! At first glance this looks to be doing what the code for def does; I guess it's a "forked" def. I may use this on my next mini-project.

– Carl Smotricz Mar 22 '10 at 10:51 1 As a rule of thumb: Don't use eval until its necessary and you know what you're doing. I'd go with intern for solving the problem at hand; this answer showed nicely that eval is not needed here. – danlei Mar 23 '10 at 0:37 2 Var.

Intern is available as the built-in Clojure function "intern" – Stuart Sierra Mar 27 '10 at 19:40 @Stuart: Thanks for the comment! I guess I ought to re-familiarise myself with the core API... I'll work this into the answer. – Micha?

Marczyk Mar 27 '10 at 20:37.

Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters. But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others.

Def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).

I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong. (Note: doall + for = doseq.).

Thanks for the reminder about doseq! I'm defining a handful of variables at the top level and just wanted to cut down on typing. – Carl Smotricz Mar 22 '10 at 10:46 2 Why not use symbols to begin with then, instead of strings?

– Brian Carper Mar 22 '10 at 22:48 Because the names I was planning to use were themselves computed (by concatenation, natch). I emphasize that I do this only for purposes of experimental, "quick and dirty" code; there are much better ways to express what I'm doing. I posted this question only because I wanted to do this in my early-draft code and was annoyed that the otherwise excellent Clojure language seemed not to support this particular jiggerpokery.

– Carl Smotricz Mar 23 '10 at 15:50 I'm still exploring the Lisp idiom and Clojure in particular. I do not plan to make dynamically created named global variables part of my regular programming repertoire. – Carl Smotricz Mar 23 '10 at 15:52.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions