#:g1: ZetalispのPKG-BIND

Posted 2010-09-11 14:47:00 GMT

LispマシンのLISPであるZetalisp/Lisp machine lispには、PKG-BINDというのがあって

(PKG-BIND "FOO"
  (DEFUN FOO (N) N))
のように指定した範囲だけパッケージが指定できます。
パッケージの仕組みからして違うのでそもそもCLで再現できるのか分からないのですが、今日Twitterでやりとりをしている中でS式を一旦文字列にしてREAD-FROM-STRINGすれば良いかと思い
(DEFMACRO PKG-BIND (&WHOLE WHOLE PKG &BODY BODY)
  (LET ((PKG-BIND-PKG (PACKAGE-NAME (SYMBOL-PACKAGE (CAR WHOLE)))))
    `(LET ((*PACKAGE* (FIND-PACKAGE ,PKG)))
       (EVAL
        (READ-FROM-STRING
         ,(WRITE-TO-STRING 
           `(PROGN 
              (IMPORT (READ-FROM-STRING
                       ,(FORMAT NIL 
                                "~A::PKG-BIND"
                                PKG-BIND-PKG)))
              ,@BODY)))))))
みたいなものを作成しました。
ZetalispのPKG-BINDが入れ子にできるのかどうか不明なのですが、とりあえず入れ子に対応。
(DEFPACKAGE :FOO (:USE :CL))
(PKG-BIND :FOO
  (DEFUN FOO (N) N)

(DEFPACKAGE :BAR (:USE :CL)) (PKG-BIND :BAR (DEFUN BAR (N) N)

(DEFPACKAGE :BAZ (:USE :CL)) (PKG-BIND :BAZ (DEFUN BAZ (CL-USER::N) CL-USER::N))))

(LIST (FOO::FOO 8) (BAR::BAR 8) (BAZ::BAZ 8)) ;⇒ (8 8 8)

EVALを使うので外部のレキシカルな変数は取り込めないのですが、この方法以外でインターンするシンボルを選り分けるのは、なかなか面倒なので、まあ、これで良いかなと妥協。
以前はボディを走査してシンボルのパッケージを書き換えるという方法を試してみていました。
書き方が悪かった所為で上手く行かなかったような気もするので、シンボルを操作する方法でも書いてみたいと思います。

comments powered by Disqus