COMPILER-LETの使い道 — #:g1

Posted 2010-11-14 14:57:00 GMT

COMPILER-LETは、CLtL2までは存在したスペシャルフォームで、今でも互換性の維持のため処理系によっては、サポートしています。
- (http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node83.html)
動作としては、インタプリタでは、束縛する変数をスペシャル宣言したletと同じ動きをするのですが、コンパイラが処理すると、コンパイル時にその変数束縛が有効にされた状態でボディが評価されます。
言葉では上手く説明できないのですが、動きとしては、コンパイル時にスペシャル変数の束縛が固定される、というような感じです。

#+sbcl (import 'sb-cltl2:compiler-let)

(defmacro foo () (if *flag* :hello :bye))

(list *flag* (foo)) ;=> (NIL :BYE)

(defmacro bar () (foo))

(list *flag* (bar)) ;=> (NIL :BYE)

(defmacro baz () `(let ((*flag* t)) ;マクロ展開後には効くが展開時には効かない (foo)))

(list *flag* (baz)) ;=> (NIL :BYE)

(defmacro quux () `(compiler-let ((*flag* t)) (foo)))

(list *flag* (quux)) ;=> (NIL :HELLO)

これはどういうところで使うんだろうと常々思っていましたが、Seriesがマクロの展開にスペシャル変数をフラグとして使っていて、このフラグの値を制御をしたい場合に必要になりました。
具体的には、SERIES::*SERIES-IMPLICIT-MAP*という変数があり、これがマクロ展開で参照されるのですが、このフラグを参照するマクロを使って、さらにその上にマクロを組むにあたって、大域変数の値によらず常にSERIES::*SERIES-IMPLICIT-MAP*がTの状態で展開されて欲しいということになりました。
COMPILER-LETは、用途が曖昧で大抵の局面では、MACROLETや、SYMBOL-MACROLETで置き換え可能ということで廃止になったようです。
-(http://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm)
に置き換えの説明があるのですが、やはり色々とややこしい気がします…

comments powered by Disqus