Shammer's Philosophy

My private adversaria

関数を生成するマクロ・その5

関数を生成するマクロ・その4 - Shammerismでの課題を解決できた。バッククォートより後の内容が展開式になるが、展開式の中で展開式で宣言される defun の関数名を作成していたのが原因だった。つまりはケアレスミスのようなものだ。うまくいかなかった例は以下のように試していた。

? (defmacro generate-semaphore-getter (name)
`(let ((semaphore (make-semaphore))
       (getter (string-upcase (concatenate 'string "get-semaphore-for-" ,name))))
    (defun ,(intern getter) () semaphore)))
;Compiler warnings :
;   In GENERATE-SEMAPHORE-GETTER: Undeclared free variable GETTER
GENERATE-SEMAPHORE-GETTER
?

ここで、(defun ,(intern getter) () semaphore) の ,(intern getter)を、(intern getter)としたり、',(intern getter) や `,(intern getter) としてみたりと、いろいろとやったがどこかしらでエラーになる。問題は defun の中身じゃなくて、getter をバッククォートの中で宣言していたことだった。間違いに気付いて変更したバージョンが以下。

? (defmacro generate-semaphore-getter (name)
(let ((getter (string-upcase (concatenate 'string "get-semaphore-for-" name))))
  `(let ((semaphore (make-semaphore)))
     (defun ,(intern getter) () semaphore))))
GENERATE-SEMAPHORE-GETTER
? (pprint (macroexpand-1 '(generate-semaphore-getter "XXX"))) 

(LET ((SEMAPHORE (MAKE-SEMAPHORE)))
  (DEFUN GET-SEMAPHORE-FOR-XXX () SEMAPHORE))
? (generate-semaphore-getter "xxx")
GET-SEMAPHORE-FOR-XXX
? (get-semaphore-for-xxx)
#<SEMAPHORE #x302000DE321D>
? (eq (get-semaphore-for-xxx) (get-semaphore-for-xxx))
T
?

これで実装もスッキリした。この例では、検証のために関数を生成するマクロ・その4 - Shammerismでは入れていた public-symbol とかを省略しているけれども、、、念の為書いておこう。

? (defmacro generate-semaphore-getter (name)
(let ((getter (string-upcase (concatenate 'string "get-semaphore-for-" name))))
  `(let ((semaphore (make-semaphore)))
     (defun ,(intern getter) () semaphore)
     (public-symbol ,(intern getter))
     (export-public-symbol))))
GENERATE-SEMAPHORE-GETTER
? (pprint (macroexpand-1 '(generate-semaphore-getter "YYY")))

(LET ((SEMAPHORE (MAKE-SEMAPHORE)))
  (DEFUN GET-SEMAPHORE-FOR-YYY () SEMAPHORE)
  (PUBLIC-SYMBOL GET-SEMAPHORE-FOR-YYY)
  (EXPORT-PUBLIC-SYMBOL))
? (generate-semaphore-getter "YYY")
NIL
? (get-semaphore-for-yyy)
#<SEMAPHORE #x302000E076CD>
? (eq (get-semaphore-for-yyy) (get-semaphore-for-yyy))
T
?