Next: , Previous: , Up: プログラム構造   [Contents][Index]


2.2 評価の時間

通常、バイトコンパイラはコンパイルするファイルのフォームを実際には 実行しない。たとえば、ファイルが(setq foo t)を含む場合、 コンパイルすることは実際にはtfooに設定しない。 setqがトップレベルフォーム(すなわちdefunまたは他の フォームに囲まれていない)だったとしてもそれは真である。しかし、ある トップレベルフォームをコンパイル時に評価させたい場合がある。たとえば、 ファイルの残りの部分が定義されたマクロを参照できるように、コンパイラは defmacroフォームをコンパイル時に実際に評価する。

Special Form: eval-when (situations...) forms...

このフォームは本体formsがいつ評価されるかを制御する。 situationsリストはシンボルcompileload、そして eval(または長いANSIの同等物、:compile-toplevel:load-toplevel、そして:execute)のいずれの集合を 含んでもよい。

eval-whenフォームは、トップレベルフォームとして コンパイルされているかどうかによって異なって扱われる。つまり、 byte-compile-fileのようにファイルやコードのバッファを コンパイルするコマンドによってコンパイルされているときに特別に扱われ、 文字通りファイルのトップレベルかprognの内部のトップレベルに 現れる。

コンパイルされたトップレベルのeval-whenには、compilesituationsリストにある場合には、forms本体はコンパイル時に 実行され、loadsituationsリストにある場合には、 formsは(ロード時に実行されるように)ファイルに書かれる。

コンパイルされていないトップレベルフォームには、状況evalのみが 関係する。(これはインタプリタが実行するフォーム、 byte-compile-fileではなくbyte-compileでコンパイルされた フォーム、トップレベルではないフォームを含む。 ) evalが 指定された場合、eval-whenprognのように振る舞い、 そうでない場合はnil(forms本体を無視する)のように 振る舞う。

eval-whenが入れ子の場合、規則はさらに微妙になる; ぞっとするような詳細(そしてぞっとするような例)はSteele(第2版)を 調べること。

単純な例:

;; top-level forms in foo.el:
(eval-when (compile)           (setq foo1 'bar))
(eval-when (load)              (setq foo2 'bar))
(eval-when (compile load)      (setq foo3 'bar))
(eval-when (eval)              (setq foo4 'bar))
(eval-when (eval compile)      (setq foo5 'bar))
(eval-when (eval load)         (setq foo6 'bar))
(eval-when (eval compile load) (setq foo7 'bar))

foo.elがコンパイルされると、これらの変数がコンパイル自身の間に設定される:

foo1  foo3  foo5  foo7      ; `compile'

foo.elcがロードされると、これらの変数が設定される:

foo2  foo3  foo6  foo7      ; `load'

ロードされたfoo.elがコンパイルされていないと、これらの変数が設定される:

foo4  foo5  foo6  foo7      ; `eval'

仮にこれら7個のeval-whendefun内部にあれば、最初の3個は nilと同等であり、最後の4個は対応するsetqと同等である。

(eval-when (load eval) …)はあらゆるコンテキストで (progn …)と同等であることに注意せよ。コンパイラは defmacro(多少)やrequireのようないくつかの トップレベルフォームを(eval-when (compile load eval) …)で 包まれているかのように扱う。

Emacs 19はeval-whenと関係がある2個の特殊形式を含む。そのうちの 1個であるeval-when-compileは、どのeval-when構文要素と 完全に同等ではなく以下に記述される。このパッケージはEmacs 18 ユーザのためにeval-when-compileの1個の版を定義する。

他方のフォーム(eval-and-compile …)は ‘(eval-when (compile load eval) …)’と正確に同等なので、それ 自身はこのパッケージで定義されていない。

Special Form: eval-when-compile forms...

formsはコンパイル時に評価される;実行時、このフォームは結果として 生じる値の引用された定数のように振る舞う。トップレベルで使われると、 eval-when-compileはちょうど‘eval-when (compile eval)’ のようである。他のコンテキストでは、eval-when-compileは効率 その他の理由でコードがコンパイル時に1度だけ評価されることを許す。

このフォームは真のCommon Lispの‘#.’文法に類似している。

Special Form: load-time-value form

formはロード時に評価される; 実行時、このフォームは結果として 生じる値の引用された定数のように振る舞う。

初期のCommon Lispはこれに類似した‘#,’文法を持っていたが、ANSI Common Lispはload-time-valueで置き換えてよりよく定義された 意味論を与えた。

コンパイルされたファイルでは、load-time-valueform.elcファイルがロードされたときに評価され引用された定数だったか のように使われるように準備する。byte-compile-fileではなく byte-compileでコンパイルされたコードでは、効果は eval-when-compileと同一である。コンパイルされていないコードでは、 eval-when-compileload-time-valueは正確にprognの ように振る舞う。

(defun report ()
  (insert "This function was executed on: "
          (current-time-string)
          ", compiled on: "
          (eval-when-compile (current-time-string))
          ;; or '#.(current-time-string) in real Common Lisp
          ", and loaded on: "
          (load-time-value (current-time-string))))

バイトコンパイルされると、上のdefunの例は下記のコード (またはもちろんそのコンパイルされた同等のもの)を.elcファイルに 生じる:

(setq --temp-- (current-time-string))
(defun report ()
  (insert "This function was executed on: "
          (current-time-string)
          ", compiled on: "
          '"Wed Jun 23 18:33:43 1993"
          ", and loaded on: "
          --temp--))

Next: , Previous: , Up: プログラム構造   [Contents][Index]