binding - Alcance variable+eval en Clojure
let (1)
1 .:
La razón por la que esto no funciona es (más o menos) dada en la página que vinculó:
It is an error if there is no global var named by the symbol […]
Y:
[…]
Se realiza una búsqueda en el espacio de nombres actual para ver si hay una asignación del símbolo a una var. Si es así, el valor es el valor de la unión de la var a la que hace referencia el símbolo.
Es un error.
eval
evalúa formularios en un entorno léxico vacío ( null en CL-lingo). Esto significa que no puede acceder a los enlaces de variables léxicas desde el alcance de la persona que llama. Además, el binding
crea nuevos enlaces para vars existentes, por lo que no puede usarlo "por sí mismo", sin haber declare
o def
las variables que intenta vincular. Además, las variables léxicas (al menos en CL, pero me sorprendería si este no fuera el caso de Clojure) ya no existían en el tiempo de ejecución: se traducen a direcciones o valores.
Véase también mi post más antiguo sobre este tema.
2 .:
Entonces, tienes que usar variables dinámicas. Puede evitar la def
explícita, pero al menos todavía tiene que declare
(cuáles son los nombres var de las def
sin enlaces):
user=> (declare ^:dynamic x)
#''user/x
user=> (binding [x 10] (eval ''(prn x)))
10
nil
Por cierto: supongo que sabes por qué necesitas una evaluación y que su uso se considera malo cuando otras soluciones serían apropiadas.
En Clojure,
(def x 3)
(eval ''(prn x))
imprime 3, mientras que
(let [y 3]
(eval ''(prn y)))
y
(binding [z 3] (eval ''(prn z)))
generar una excepción ''No se puede resolver var''.
Según http://clojure.org/evaluation , eval
, load-string
, etc., generan espacios de nombres temporales para evaluar sus contenidos. Por lo tanto, esperaría que ninguno de los ejemplos de código anteriores funcione, ya que (def x 3)
se realiza en mi espacio de nombres actual, no en el creado por eval
.
- ¿Por qué funciona el primer ejemplo de código y no los dos últimos?
- ¿Cómo puedo
eval
un formulario con variables enlazadas sin usardef
?
¡Gracias!