Actualizada para tomar en cuenta el comentario de Stuart Sierra (mencionando clojure.core/intern
).
Usando eval
aquí está bien, pero puede ser interesante saber que no es necesario, independientemente de si ya se sabe que los Vars ya existen. De hecho, si se sabe que existen, entonces creo que la siguiente solución alter-var-root
es más limpia; si no existieran, entonces no insistiría en que mi proposición alternativa sea mucho más limpia, pero parece hacer el código más corto (si no tomamos en cuenta la sobrecarga de tres líneas para una definición de función), entonces solo publicaré para su consideración.
Si el Var se sabe que existe:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
por lo que podría hacer
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(Si el mismo valor se iba a utilizar para todos Vars, podría utilizar (repeat value)
para el argumento final para mapear o simplemente ponerlo en la función anónima.)
Si el Vars podría ser necesario crear, a continuación, en realidad se puede escribir una función para hacer esto (una vez más, que no necesariamente pretendo que esto sea más limpio que eval
, pero de todos modos - sólo para el interés de la misma):
(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)))
Tenga en cuenta que si un Var resulta ya han sido internados con el nombre dado en el espacio de nombres dado, entonces esto no cambia nada en el caso solo argumento o simplemente restablece el Var a la dado un nuevo valor en el caso de dos argumentos. Con esto, se puede resolver el problema original de este modo:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Algunos ejemplos adicionales:
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
Respuesta más concisa y directa (¿posible?). Te di el tickmark y espero que sepp2k no esté enojado por perderlo. ¡Gracias! –