Alcance variable + evaluación en Clojure

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, espero que ninguna de las muestras de código anteriores funcione, ya que (def x 3) se realiza en mi espacio de nombres actual, no en el creado por eval .

  1. ¿Por qué funciona la primera muestra de código y no las dos últimas?
  2. ¿Cómo puedo eval un formulario con variables vinculadas sin usar def ?

¡Gracias!

1 .:

La razón por la que esto no funciona se da (más o menos) en la página que vinculó:

 It is an error if there is no global var named by the symbol […] 

Y:

[…]

  1. 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 vinculación de la var referida por el símbolo.

  2. Es un error

eval evalúa formularios en un entorno léxico vacío ( nulo en CL-lingo). Esto significa que no puede acceder a enlaces de variables léxicas desde el scope de la persona que llama. Además, el binding crea nuevas vinculaciones para los valores existentes, por lo que no puede usarlo “solo”, sin declare ni def las variables que intenta vincular. Además, las variables léxicas (al menos en CL, pero me sorprendería que este no fuera el caso de Clojure) ya dejaron de existir en tiempo de ejecución: se traducen en direcciones o valores.

Ver también mi publicación anterior sobre este tema.

2 .:

Entonces, debes usar variables dinámicas. Puede evitar la def explícita, pero todavía necesita al menos declare (que def s var nombres 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 eval, y que su uso se considera malo cuando otras soluciones serían apropiadas.