関数を生成するマクロ・その2
とあるパッケージの中で、とある関数を宣言してから、それを外部で使用させるためにエクスポートする、という処理を行う必要があるが(まあ、エクスポートしなくても unintern されていなければ::でアクセスできるのだが)、これをやるのが結構めんどくさいし、ソースコードも雑になる。しかも、アクセッサについてはほぼ外部に公開する必要がある。というわけで、この処理のコードもマクロに含めてしまおう、となった。関数を生成するマクロ・その1 - Shammerismで書いたコードに export の処理を追加。
? (defmacro generate-semaphore-accessor (name) `(let ((semaphore (make-semaphore))) (defun ,name () semaphore) (export ,name))) GENERATE-SEMAPHORE-ACCESSOR ? (generate-semaphore-accessor get-my-semaphore) ;Compiler warnings : ; In an anonymous lambda form at position 29: Undeclared free variable GET-MY-SEMAPHORE > Error: Unbound variable: GET-MY-SEMAPHORE > While executing: #<Anonymous Function #x302000F88DEF>, in process listener(1). > Type :POP to abort, :R for a list of available restarts. > Type :? for other options. 1 > a ? (get-my-semaphore) #<SEMAPHORE #x302000F87D9D> ? (defmacro generate-semaphore-accessor (name) `(let ((semaphore (make-semaphore))) (export ,name) (defun ,name () semaphore))) GENERATE-SEMAPHORE-ACCESSOR ? (generate-semaphore-accessor get-test-01-semaphore) ;Compiler warnings : ; In an anonymous lambda form at position 29: Undeclared free variable GET-TEST-01-SEMAPHORE > Error: Unbound variable: GET-TEST-01-SEMAPHORE > While executing: #<Anonymous Function #x302000FAE6FF>, in process listener(1). > Type :POP to abort, :R for a list of available restarts. > Type :? for other options. 1 > q ? (export get-test-01-semaphore) > Error: Unbound variable: GET-TEST-01-SEMAPHORE > While executing: CCL::CHEAP-EVAL-IN-ENVIRONMENT, in process listener(1). > Type :GO to continue, :POP to abort, :R for a list of available restarts. > If continued: Retry getting the value of GET-TEST-01-SEMAPHORE. > Type :? for other options. 1 > q ? (defmacro export-1 (name) `(export ',name)) EXPORT-1 ? (export-1 get-test-01-semaphore) T ?
最初はエラーばかりだったけれども、export は引数をクォートしていないといけないのに対し、defun は真逆というのが原因のようだ。マクロをうまく機能させるには、',という形でシンボルを評価しなければならないこともあるようだ。うーむ。。。まだまだ覚えないといけないことはたくさんありそうだ。