Frage

Ich habe einen s-Ausdruck auf eine Variable in Common Lisp gebunden:

(defvar x '(+ a 2))

Jetzt möchte ich eine Funktion erstellen, die, wenn sie aufgerufen, den Ausdruck im Rahmen auswertet, in der sie definiert wurde. Ich habe dies versucht:

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

und

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

Aber beides schafft ein Problem: EVAL wird den Code auf der obersten Ebene bewerten, so kann ich nicht Variablen erfassen in dem Ausdruck enthalten ist. Beachten Sie, dass ich nicht die LET Form in der EVAL setzen kann. Gibt es eine Lösung?

EDIT: Also, wenn es nicht Lösung des EVAL Problem ist, wie kann es sonst getan werden

EDIT: Es war eine Frage, was genau ich versuche, mich zu tun. Ich schreibe einen Compiler. Ich mag einen s-Ausdruck mit Variablen in der lexikalischen Umgebung geschlossen akzeptieren, wenn der Ausdruck definiert ist. Es kann in der Tat besser, es als ein Makro zu schreiben.

War es hilfreich?

Lösung

Sie müssen den Code erstellen, der die notwendigen Bindungen hat. Wickeln Sie ein LET um Ihren Code und binden jede Variable, die Sie wollen in Ihrem Code zur Verfügung stellen:

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

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

Andere Tipps

CLISP implementiert eine Erweiterung ein Formular in der lexikalischen Umgebung zu bewerten. Aus der Tatsache, dass es eine Erweiterung ist, ich vermute, Sie nicht, dass in einer normgerechten Art und Weise tun können.

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

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

Was ist das eigentliche Problem, das Sie lösen möchten? Wahrscheinlich versucht man es den falschen Weg zu bewältigen. Lexikalische Bindungen sind für Dinge, die lexikalisch in ihrem Umfang nicht für zufällige Sachen erscheinen Sie von außen erhalten.

Vielleicht möchten Sie eine dynamische Schließung? So etwas in Common Lisp nicht existiert, obwohl es in einigen Lisp Dialekte tut (wie Pico Lisp, soweit ich verstehen).

Beachten Sie, dass können Gehen Sie folgendermaßen vor, die ähnlich ist:

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

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

Ich rate Ihnen schwer, darüber nachzudenken, ob Sie wirklich wollen, though.

In Common Lisp können Sie definieren * evalhook * Welche ermöglicht es Ihnen, eine Umgebung passieren (eval ...). *evalhook* ist plattformunabhängig.

Es ist möglich, COMPILE zu verwenden den Ausdruck in Funktion zu kompilieren und dann PROGV verwenden, um die kompilierte Funktion in der Umgebung FUNCALL wo Variablen dynamisch festgelegt werden. Oder besser, verwenden Sie COMPILE den Ausdruck in Funktion zu kompilieren, die Variablen akzeptiert.

Compile nimmt die Funktionsdefinition als Liste und verwandelt es in Funktion. Im Fall von SBCL wird diese Funktion in Maschinencode kompiliert und ausgeführt werden effizient.

Erste Option (mit kompilieren und progv):

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

Zweite Option:

(defvar *fn* (compile nil '(lambda (a) (+ a 2))))
(funcall *fn* 4)
=>
6
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top