Lisp演算子に関する多くのドキュメントを読んだ後でeval-when
も、その使用法を理解できません。この演算子を使用すると、式の評価時間を制御できることはわかっていますが、これが当てはまる例がわかりません。
よろしく、utxeee。
Lisp演算子に関する多くのドキュメントを読んだ後でeval-when
も、その使用法を理解できません。この演算子を使用すると、式の評価時間を制御できることはわかっていますが、これが当てはまる例がわかりません。
よろしく、utxeee。
Lispファイルのコンパイル
たとえば、Lispファイルのコンパイルを考えてみましょう。Lispコンパイラはトップレベルのフォームを処理します。これらは、任意のLisp形式、DEFUN、DEFMACROS、DEFCLASS、関数呼び出しなどです。
ファイルコンパイラがどのように機能するかについての全体的な話は、ここで説明するには複雑すぎますが、いくつかのことがあります。
ファイルコンパイラは、(DEFUN foo () )
フォームのコードを生成します。ただし、defunフォームは実行されません。したがって、コンパイル中に関数があることがFOO
わかりますが、コンパイル中に「FOO」のコードは使用できません。コンパイラはコンパイルされたファイルのコードを生成しますが、それをメモリに保持しません。コンパイル時にそのような関数を呼び出すことはできません。
マクロの場合、これはわずかに異なる動作をします(DEFMACRO BAZ ...)
。ファイルコンパイラは、マクロをコンパイルしてそこにあることに注意するだけでなく、コンパイル時にマクロを使用できるようにします。コンパイラ環境にロードされます。
したがって、ファイル内のフォームのシーケンスを想像してみてください。
(defmacro baz ...)
(defun foo () (baz ...))
これが機能するのは、ファイルコンパイラがマクロBAZ
を認識しており、のコードをコンパイルするときにFOO
、マクロ形式を展開できるためです。
次に、次の例を見てみましょう。
(defun bar (form) ...)
(defmacro baz (form) (bar form))
(defun foo () (baz ...))
上記は機能しません。これで、マクロBAZ
は関数BAR
を呼び出して関数を使用します。コンパイラが関数をコンパイルしようとすると、のコードがコンパイル時環境にロードされないため、呼び出すことができないため、マクロをFOO
展開できません。BAZ
BAR
BAR
これには2つの解決策があります。
BAR
例EVAL-WHEN
:
(eval-when (:compile-toplevel :execute :load-toplevel)
(defun bar (form) ...)
)
(defmacro baz (form) (bar form))
(defun foo () (baz ...))
ここで、EVAL-WHEN
はファイルコンパイラに、コンパイル中にDEFUNフォームを実際に実行するように指示します。これにより、ファイルコンパイラはコンパイルBAR
時にの定義を認識できるようになります。したがって、後で、の使用法のマクロ展開中にファイルコンパイラが呼び出す必要があるときに使用できます。BAR
BAZ
:compile-toplevel
ファイルのコンパイル後に関数が不要になる場合にのみ使用できます。後で使用する場合は、ロードされることを確認する必要があります。
したがってEVAL-WHEN
、特定のコードを実行する必要があるかどうかを指定できます
EVAL-WHEN
ユーザーコードではあまり使用されません。それを使用する場合は、本当に必要かどうかを自問する必要があります。