15

Lisp演算子に関する多くのドキュメントを読んだ後でeval-whenも、その使用法を理解できません。この演算子を使用すると、式の評価時間を制御できることはわかっていますが、これが当てはまる例がわかりません。

よろしく、utxeee。

4

1 に答える 1

28

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展開できません。BAZBARBAR

これには2つの解決策があります。

  1. 別のファイルを使用して、以前にコンパイルしてロードします。BAR
  2. EVAL-WHENを使用する

EVAL-WHEN

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

 (defmacro baz (form) (bar form))

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

ここで、EVAL-WHENはファイルコンパイラに、コンパイル中にDEFUNフォームを実際に実行するように指示します。これにより、ファイルコンパイラはコンパイルBAR時にの定義を認識できるようになります。したがって、後で、の使用法のマクロ展開中にファイルコンパイラが呼び出す必要があるときに使用できます。BARBAZ

:compile-toplevelファイルのコンパイル後に関数が不要になる場合にのみ使用できます。後で使用する場合は、ロードされることを確認する必要があります。

したがってEVAL-WHEN、特定のコードを実行する必要があるかどうかを指定できます

  • ファイルのコンパイル中
  • ファイルのロード中
  • 実行中

EVAL-WHENユーザーコードではあまり使用されません。それを使用する場合は、本当に必要かどうかを自問する必要があります。

于 2012-05-20T17:07:59.177 に答える