compilazione di un file Lisp
Prendiamo ad esempio la compilazione di un file Lisp. Il compilatore Lisp elabora i moduli di livello superiore. Questi possono essere forme arbitrarie Lisp, Defuns, DEFMACROS, DEFCLASS, chiamate di funzione, ...
L'intera storia come funziona il compilatore di file è troppo complesso da spiegare qui, ma un paio di cose:
il compilatore di file genera il codice per un modulo (DEFUN foo())
. Ma non esegue la forma di defun. Pertanto durante la compilazione è noto che esiste una funzione FOO
, ma il codice di "FOO" non è disponibile durante la compilazione. Il compilatore genera il codice per il file compilato, ma non lo tiene in memoria. Non è possibile chiamare tale funzione in fase di compilazione.
per i macro funziona in modo leggermente diverso: (DEFMACRO BAZ ...)
. Il compilatore di file non solo compila la macro e nota che è lì, ma renderà anche la macro disponibile al momento della compilazione. È caricato nel compilatore ambiente.
Così immaginare la sequenza di forme in un file:
(defmacro baz ...)
(defun foo() (baz ...))
Questo funziona perché il compilatore di file conosce la macro BAZ
e quando compila il codice per FOO
, allora è possibile espandere la forma di macro .
Ora diamo un'occhiata al seguente esempio:
(defun bar (form) ...)
(defmacro baz (form) (bar form))
(defun foo() (baz ...))
Sopra non funzionerà. Ora la macro BAZ
utilizza la funzione BAR
chiamando. Quando il compilatore tenta di compilare la funzione FOO
, non è possibile espandere la macro BAZ
, perché non è possibile chiamare BAR
perché il codice di BAR
non è stato caricato nell'ambiente di compilazione.
ci sono due soluzioni a questo:
- compilazione e carico
BAR
in precedenza utilizzando un file separato.
- Usa EVAL-WHEN
Esempio per EVAL-WHEN
:
(eval-when (:compile-toplevel :execute :load-toplevel)
(defun bar (form) ...)
)
(defmacro baz (form) (bar form))
(defun foo() (baz ...))
Ora il EVAL-WHEN
istruisce il file compilatore per eseguire effettivamente la forma defun durante la compilazione.L'effetto di questo è: il compilatore di file ora conosce la definizione di BAR
allo tempo di compilazione. Pertanto è disponibile in seguito, quando il compilatore di file deve chiamare BAR
durante l'espansione macro dell'uso di BAZ
.
Uno potrebbe utilizzare solo :compile-toplevel
, quando la funzione non sarebbe necessaria dopo la compilazione del file. Se viene utilizzato in seguito, è necessario accertarsi che venga caricato.
Così EVAL-WHEN
permette di specificare se un particolare pezzo di codice dovrebbe essere eseguito
- durante la compilazione di un file
- durante il caricamento di un file
- durante l'esecuzione
EVAL-WHEN
è non usato così spesso nel codice utente. Se lo usi, dovresti chiederti se ne hai davvero bisogno.
Ciao Rainer, ma perché abbiamo bisogno di usare i flag: execute e: load-top-level in questo uso di eval-when? – utxeee
Rainer ringrazia ancora per la tua risposta redigendo la risposta precedente: D Ma il mio dubbio rimane, perché ho bisogno di usare i flag: load-top-level e: execute. Dal tuo testo vedo che dovremmo usare il flag: load-top-level se la funzione viene usata in seguito. Quindi, perché non è necessario utilizzare eval-when con: load-top-level in tutte le altre funzioni che verranno utilizzate in seguito? – utxeee
@utxeee: load-top-level è un valore predefinito durante la compilazione, quando non c'è EVAL-WHEN. –