2011-06-03 11 views
16

En Clojure,alcance Variable + eval en Clojure

(def x 3) 
(eval '(prn x)) 

grabados 3, mientras que

(let [y 3] 
    (eval '(prn y))) 

y

(binding [z 3] (eval '(prn z))) 

generar un 'No se puede resolver var' excepción.

De acuerdo con http://clojure.org/evaluation, eval, load-string, etc. generan espacios de nombres temporales para evaluar sus contenidos. Por lo tanto, espero 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.

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

¡Gracias!

Respuesta

14

1 .:

La razón esto no funciona es (más o menos) que figura en la página enlazada:

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 nombre 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 formas en un vacío (null en CL-jerga) entorno léxico. Esto significa que no puede acceder a enlaces de variables léxicas desde el alcance de la persona que llama. Además, binding crea nuevos enlaces para VARs existentes, por lo que no se puede utilizar "por sí mismo", sin tener declare d o def ed las variables intenta enlazar. 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.

Véanse también mis older post sobre este tema.

2 .:

Por lo tanto, usted tiene que utilizar variables dinámicas.Usted puede evitar la explícita def, pero aún así, al menos que tenga que declare ellos (que def s nombres var sin ataduras):

user=> (declare x) 
#'user/x 
user=> (binding [x 10] (eval '(prn x))) 
10 
nil 

Por cierto: Supongo que sabe por qué necesita eval, y que su uso es considered evil cuando otras soluciones serían apropiadas.

+3

Tenga en cuenta que esto no funcionará en Clojure 1.3. Tendrás que usar '(declare ^: dinámico x)'. – danlei

+0

¡Gracias! Ahora comprendo mi problema: asumí que el "alcance léxico nulo" también significaba un "espacio de nombres nulo", pero las pruebas rápidas revelan que 'eval' funciona dentro del espacio de nombres actual, por lo que tiene acceso a vars de espacio de nombres pero no variables léxicas Muy buena respuesta, ¡y tus enlaces también fueron útiles! – gilesc

+0

¡De nada! Me alegra que haya ayudado. Además, gracias por aceptar. – danlei