Pregunta

Tengo una expresión s vinculada a una variable en Common Lisp:

(defvar x '(+ a 2))

Ahora quiero crear una función que cuando sea llamada, evalúe la expresión en el ámbito en el que se definió. He intentado esto:

(let ((a 4))
  (lambda () (eval x)))

y

(let ((a 4))
  (eval `(lambda () ,x)))

Pero ambos crean un problema: EVAL evaluará el código en el nivel superior, por lo que no puedo capturar las variables contenidas en la expresión. Tenga en cuenta que no puedo poner el formulario LET en el EVAL. ¿Hay alguna solución?

EDIT: Entonces, si no hay una solución al problema EVAL, ¿de qué otra manera se puede hacer?

EDITAR: Hubo una pregunta sobre qué es exactamente lo que intento hacer. Estoy escribiendo un compilador. Quiero aceptar una s-expresión con variables cerradas en el entorno léxico donde se define la expresión. De hecho, puede ser mejor escribirlo como una macro.

¿Fue útil?

Solución

Necesitas crear código que tenga los enlaces necesarios. Envuelva un LET alrededor de su código y enlace todas las variables que desee que estén disponibles en su código:

(defvar *x* '(+ a 2))

(let ((a 4))
  (eval `(let ((a ,a))
           ,*x*)))

Otros consejos

CLISP implementa una extensión para evaluar un formulario en el entorno léxico. Por el hecho de que es una extensión, sospecho que no puede hacerlo de una manera que cumpla con los estándares.

(ext:eval-env x (ext:the-environment))

Consulte http://clisp.cons.org/impnotes.html#eval- environ .

¿Cuál es el problema real que quieres resolver? Lo más probable es que estés tratando de abordarlo de la manera incorrecta. Los enlaces léxicos son para cosas que aparecen léxicamente dentro de su alcance, no para cosas aleatorias que se obtienen de afuera.

¿Tal vez quieres un cierre dinámico? Tal cosa no existe en Common Lisp, aunque sí en algunos dialectos de Lisp (como Pico Lisp, por lo que yo entiendo).

Tenga en cuenta que puede hacer lo siguiente, que es similar:

(defvar *a*)
(defvar *x* '(+ *a* 2))  ;'

(let ((a 10))
  ;; ...
  (let ((*a* a))
    (eval *x*)))

Sin embargo, te aconsejo que pienses bien si realmente quieres esto.

En Common Lisp puede definir * evalhook * Lo que le permite pasar un entorno a (eval ...) . * evalhook * es independiente de la plataforma.

Es posible usar COMPILAR para compilar la expresión en función y luego usar PROGV para FUNCALLAR la función compilada en el entorno donde las variables se establecen dinámicamente. O, mejor, use COMPILE para compilar la expresión en una función que acepte variables.

Compile acepta la definición de función como una lista y la convierte en función. En el caso de SBCL, esta función se compila en un código de máquina y se ejecutará de manera eficiente.

Primera opción (usando compile y progv):

(defvar *fn* (compile nil '(lambda () (+ a 2)))
(progv '(a) '(4) (funcall *fn*))
=>
6

Segunda opción:

(defvar *fn* (compile nil '(lambda (a) (+ a 2))))
(funcall *fn* 4)
=>
6
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top