Domanda

Ho un'espressione s legata a una variabile in Common Lisp:

(defvar x '(+ a 2))

Ora voglio creare una funzione che, quando viene chiamata, valuta l'espressione nell'ambito in cui è stata definita. Ho provato questo:

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

e

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

Ma entrambi creano un problema: EVAL valuterà il codice al livello più alto, quindi non riesco a catturare le variabili contenute nell'espressione. Nota che non riesco a inserire il modulo LET nell'EVAL. C'è qualche soluzione?

EDIT: quindi se non esiste una soluzione al problema EVAL, come si può fare altrimenti?

EDIT: c'era una domanda su cosa esattamente sto provando a fare. Sto scrivendo un compilatore. Voglio accettare un'espressione s con variabili chiuse nell'ambiente lessicale in cui è definita l'espressione. Potrebbe davvero essere meglio scriverlo come macro.

È stato utile?

Soluzione

Devi creare un codice con i collegamenti necessari. Avvolgi una LET intorno al tuo codice e associa ogni variabile che vuoi rendere disponibile nel tuo codice:

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

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

Altri suggerimenti

CLISP implementa un'estensione per valutare un modulo nell'ambiente lessicale. Dal fatto che si tratta di un'estensione, sospetto che non sia possibile farlo in modo conforme allo standard.

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

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

Qual è il problema reale che vuoi risolvere? Molto probabilmente, stai cercando di affrontarlo nel modo sbagliato. I vincoli lessicali sono per cose che appaiono lessicamente nel loro ambito, non per cose casuali che ottieni dall'esterno.

Forse vuoi una chiusura dinamica? Una cosa del genere non esiste in Common Lisp, anche se in alcuni dialetti Lisp (come Pico Lisp, per quanto ho capito).

Nota che puoi fare quanto segue, che è simile:

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

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

Ti consiglio di pensare seriamente se vuoi davvero questo,

In Common Lisp puoi definire * evalhook * Che consente di passare un ambiente a (eval ...) . * evalhook * è indipendente dalla piattaforma.

È possibile utilizzare COMPILE per compilare l'espressione in funzione e quindi utilizzare PROGV per FUNCALL la funzione compilata nell'ambiente in cui le variabili sono impostate dinamicamente. O, meglio, usa COMPILE per compilare l'espressione in una funzione che accetta le variabili.

Compile accetta la definizione della funzione come elenco e la trasforma in funzione. Nel caso di SBCL, questa funzione viene compilata nel codice macchina e verrà eseguita in modo efficiente.

Prima opzione (usando compilazione e progv):

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

Seconda opzione:

(defvar *fn* (compile nil '(lambda (a) (+ a 2))))
(funcall *fn* 4)
=>
6
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top