eval-whenの挙動を確認してみた
common lispで、eval-whenの使いどころがイマイチぴんときません。
挙動を確認することで、理解が深まるといいなと思います。
処理系はSBCLです。
REPLで実行してみる
CL-USER> (eval-when (:execute)
(print 'execute))
EXECUTE
EXECUTE
CL-USER> (eval-when (:load-toplevel)
(print 'load-toplevel))
NIL
CL-USER> (eval-when (:compile-toplevel)
(print 'compile-toplevel))
NIL
:executeのみ実行されました。ロードも、コンパイルもしていないので、これはこれで納得です。
loadしてみる
eval-when.lispに保存したうえで、ロードしてみます。
(eval-when (:execute)
(print 'execute))
(eval-when (:load-toplevel)
(print 'load-toplevel))
(eval-when (:compile-toplevel)
(print 'compile-toplevel))
CL-USER> (load "eval-when.lisp")
EXECUTE
T
:executeのみevalされました。:load-toplevelがevalされないのは意外です。
compile-fileはどうか?
同じソースファイルをコンパイルしてみます。
CL-USER> (compile-file "eval-when.lisp")
; compiling file "eval-when.lisp" (written 14 APR 2022 03:24:19 AM):
; compiling (PRINT (QUOTE LOAD-TOPLEVEL))
COMPILE-TOPLEVEL
; wrote eval-when.fasl
; compilation finished in 0:00:00.001
#P"eval-when.fasl"
NIL
NIL
evalされたのは:compile-toplevel。これもまあそうかなという感じ。
ここで:load-toplevelのみがコンパイルされていますね。(3行目)
コンパイルされたファイルをloadしてみる
CL-USER> (load "eval-when.fasl")
LOAD-TOPLEVEL
T
:load-toplevelがevalされました。これはつまり、:load-toplevelのloadがコンパイルされたファイルのロードであるということですね。
小出先生のおっしゃるとおりでした。
以下、小出誠二先生のブログより引用させていただきます。
PAIP, auxfns.lisp のウォークスルー : セマンティックウェブ・ダイアリー
ここで eval-when はその囲まれたフォームをいつ評価したらよいのかを指定するための特殊形式です.もっぱら用いられるのはこのように,compile,load,eval がすべて並んだものですが,その意味はコンパイル時に評価するか(compile),コンパイルされた fasl ファイルをロードするときに評価するか(load),ソースコードを実行時に評価するか(eval) というものです.
そして compile,load,eval はそれぞれ :compile-toplevel,:load-toplevel,:execute を使うべきとされています.ではそのように直してしまいましょう.コロンをつけることをお忘れなく.
(eval-when (:execute :compile-toplevel :load-toplevel)
以前にも拝見していた記事ですが、手を動かさないと知識として定着しないということですね(反省)