2012-05-20 21 views
11

Dopo aver letto molta documentazione riguardante l'operatore Lisp , non riesco ancora a comprenderne l'utilizzo, so che con questo operatore posso controllare il tempo di valutazione delle mie espressioni ma non riesco a capire alcun esempio in cui ciò possa essere applicabile?Eval: quando viene utilizzato?

I migliori saluti, utxeee.

risposta

21

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:

  1. compilazione e carico BAR in precedenza utilizzando un file separato.
  2. 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.

+0

Ciao Rainer, ma perché abbiamo bisogno di usare i flag: execute e: load-top-level in questo uso di eval-when? – utxeee

+0

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

+0

@utxeee: load-top-level è un valore predefinito durante la compilazione, quando non c'è EVAL-WHEN. –

Problemi correlati