2012-05-20 21 views
11

Nach dem Lesen einer Vielzahl von Dokumentation in Bezug auf Lisp eval-when Operator kann ich immer noch nicht verstehen, ihre Verwendung, ich weiß mit diesem Operator kann ich die Auswertungszeit meiner Ausdrücke steuern, aber ich kann kein Beispiel herausfinden, wo dies anwendbar sein könnte?Eval-wann verwendet?

Mit freundlichen Grüßen, utxeee.

Antwort

21

Erstellung einer Lisp-Datei

Nehmen Sie zum Beispiel die Erstellung einer Lisp-Datei. Der Lisp-Compiler verarbeitet die Formulare der obersten Ebene. Diese können beliebige Lisp Formen sein, Defuns, DEFMACROS, DEFCLASS, Funktionsaufrufe, ...

Die ganze Geschichte, wie die Datei Compiler funktioniert, ist zu komplex, hier zu erklären, aber ein paar Dinge:

  • Der Dateicompiler generiert Code für ein (DEFUN foo()) Formular. Aber es führt das defun Formular nicht aus. Daher ist während der Kompilierung bekannt, dass es eine Funktion FOO gibt, aber der Code von'FOO' ist während der Kompilierung nicht verfügbar. Der Compiler generiert den Code für die kompilierte Datei, speichert sie jedoch nicht im Speicher. Sie können eine solche Funktion nicht zur Kompilierzeit aufrufen.

  • für Makros funktioniert das etwas anders: (DEFMACRO BAZ ...). Der Dateicompiler kompiliert das Makro nicht nur und notiert, dass es dort ist, sondern es wird auch das Makro zum Kompilierungszeitpunkt verfügbar machen. Es wird in den Compiler Umgebung geladen. vorstellen

So die Abfolge der Formen in einer Datei:

(defmacro baz ...) 

(defun foo() (baz ...)) 

Das funktioniert, weil die Datei Compiler das Makro BAZ kennt und wenn er den Code für FOO kompiliert, dann kann es die Makroform erweitern .

Jetzt ist das folgende Beispiel aussehen lassen:

(defun bar (form) ...) 

(defmacro baz (form) (bar form)) 

(defun foo() (baz ...)) 

Above nicht funktionieren. Jetzt verwendet das Makro BAZ die Funktion BAR, indem es es aufruft. Wenn der Compiler versucht, die Funktion FOO zu kompilieren, kann es das BAZ Makro nicht erweitern, da BAR nicht aufgerufen werden kann, da der Code BAR nicht in der Kompilierzeitumgebung geladen wird.

Es gibt zwei Lösungen für dieses:

  1. Kompilierung und Last BAR früher eine separate Datei.
  2. Verwenden EVAL-WHEN

Beispiel für EVAL-WHEN:

(eval-when (:compile-toplevel :execute :load-toplevel) 
    (defun bar (form) ...) 
) 

(defmacro baz (form) (bar form)) 

(defun foo() (baz ...)) 

Nun weist die EVAL-WHEN die Datei Compiler, um tatsächlich die DEFUN Form während der Kompilierung ausgeführt werden.Der Effekt davon ist: der Dateicompiler kennt jetzt die Definition von BAR um Kompilierungszeit. Daher ist es später verfügbar, wenn der Dateikompilierer während der Makroerweiterung der Verwendung von BARBAZ aufrufen muss.

Man könnte nur :compile-toplevel verwenden, wenn die Funktion nach dem Kompilieren der Datei nicht benötigt würde. Wenn es später verwendet wird, müssen wir sicherstellen, dass es geladen wird.

So ermöglicht EVAL-WHEN angeben, ob ein bestimmtes Stück Code sollte

EVAL-WHEN ist

  • bei der Erstellung einer Datei
  • beim Laden einer Datei
  • während der Ausführung ausgeführt werden nicht oft im Benutzercode verwendet. Wenn Sie es verwenden, sollten Sie sich fragen, ob Sie es wirklich brauchen.

+0

Hallo Rainer, aber warum müssen wir die Flags verwenden: execute und: load-top-level bei dieser Verwendung von eval-wann? – utxeee

+0

Rainer bedankt sich nochmal für deine Antwort editieren der vorherigen Antwort: D Aber mein Zweifel bleibt, warum ich die Flags benutzen muss: load-top-level und: execute. Aus Ihrem Text kann ich sehen, dass wir das Flag verwenden sollten: load-top-level, wenn die Funktion später verwendet wird. Warum brauchen wir also nicht das eval-when mit: load-top-level in allen anderen Funktionen, die später verwendet werden? – utxeee

+0

@utxeee: load-top-level ist ein Standard während der Kompilierung, wenn kein EVAL-WHEN vorhanden ist. –