Lisp本積読解消: Common Lisp 入門 | 7章 マクロ — #:g1

Posted 2017-02-12 15:01:35 GMT

今回は、Common Lisp 入門 (湯淺太一/萩谷昌己著)のマクロの章を読む。

マクロ展開関数は一般のリスト処理関数として定義できる.
すなわち,マクロ展開とはリスト処理の一種である

という明確な解説から始まって、マクロと特殊形式スペシャル・フォームの違い等を説明。実装者視点なのか細かい所の解説が多い。

組み込みマクロの解説としてsetfの解説があるが、普通のマクロよりこちらの方に力が入っている印象。
一般化変数generalized variableの説明も詳しい。

マクロの定義については、まずはバッククォートを使わないで説明が進み、局所ローカルマクロまで解説した後に、バッククォートを使った書き方を解説。
macroletの定義部内でレキシカル変数・関数が参照できないことが解説されているが、このことを解説している本は少ないと思う。

コードにすると、

(let ((x 42))
  (macrolet ((foo () x))
    (foo)))
⊳ Error: The variable x is unbound.

のようなもの。

ANSによると、

The macro-expansion functions defined by macrolet are defined in the
lexical environment in which the macrolet form appears. Declarations
and macrolet and symbol-macrolet definitions affect the local macro
definitions in a macrolet, but the consequences are undefined if the
local macro definitions reference any local variable or function
bindings that are visible in that lexical environment.

とのことで未定義動作になる。

実際試してみるとAllegro CLのインタプリタ動作では動いたりするがコンパイルするとエラー、他の処理系も軒並エラーとなる。

ふと、&environmentを使って中でマクロ展開したら良いのではないかと思い試してみた所、この方法ならどの処理系でもレキシカル変数・関数が参照できた。
しかしこれは合法なのだろうか。シンボルマクロの展開に辺りに解説が書いてありそうだが合法かどうかの記述をみつけることができなかった(乞う詳細)

(defun kou (arg)
  (let ((x arg))
    (macrolet ((x (&environment env)
                 (macroexpand 'x env)))
      (x))))

(kou 42) → 42

(defun ots (arg) (let ((x arg)) (macrolet ((x (&environment env) (symbol-macrolet ((x (macroexpand 'x env))) `(list ,x ,x ,x)))) (x))))

(ots 42)(42 42 42)

(defun hei (arg) (let ((x arg)) (flet ((hei () x)) (macrolet ((x (&environment env) (macroexpand '(hei) env))) (x)))))

(hei 42) → 42

(defun tei (arg) (let ((x arg)) (flet ((tei () x)) (macrolet ((x (&environment env) (macroexpand '(funcall #'tei) env))) (x)))))

(tei 42) → 42

注意点

CLtL1時代の本なので、special-operator-pspecial-form-pだったりする。


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus