% Function MACROEXPAND, MACROEXPAND-1
Function MACROEXPAND
, MACROEXPAND-1
macroexpand
form &optional env => expansion, expanded-p
macroexpand-1
form &optional env => expansion, expanded-p
form - フォーム
env - 環境オブジェクト。デフォルトはnil
。
expansion - フォーム
expanded-p - generalized-boolean
macroexpand
とmacroexpand-1
は、マクロを展開します。
もしformがマクロフォームであれば、
macroexpand-1
は一度だけマクロフォームを呼び出して展開します。
macroexpand
は、マクロフォームではなくなるまでformを繰り返し展開します。
実際にmacroexpand
は、
macroexpand-1
を第二返却値がnil
になるまで
繰り返し呼び出します。
もしformがマクロフォームならば、 expansionはマクロ展開の結果であり、 expanded-pはtrueです。 それ以外のときは、expansionは与えられたformそのものであり、 expanded-pはfalseです。
マクロ展開は次のようにして行われます。
macroexpand-1
は、formがマクロフォームであると決定すると、
適用可能なマクロかシンボルマクロの展開関数を取得します。
*macroexpand-hook*
の値は関数であることを強制し、
3つの引数を持つ関数として呼び出しを行います。
引数は展開関数とformとenvです。
この呼び出しによって得られた値は、formの展開として受け取ります。
グローバル環境下のマクロ定義に加えて、
env内に定義されている
macrolet
とsymbol-macrolet
によって確立された
ローカルマクロも考慮されます。
もしformのみが引数に指定されたときは、
環境はnull
として効果があり、
ただdefmacro
によって確立された
グローバルマクロの定義のみが考慮されます。
マクロ定義はローカル関数の定義によってシャドウされます。
(defmacro alpha (x y) `(beta ,x ,y)) => ALPHA
(defmacro beta (x y) `(gamma ,x ,y)) => BETA
(defmacro delta (x y) `(gamma ,x ,y)) => EPSILON
(defmacro expand (form &environment env)
(multiple-value-bind (expansion expanded-p)
(macroexpand form env)
`(values ',expansion ',expanded-p))) => EXPAND
(defmacro expand-1 (form &environment env)
(multiple-value-bind (expansion expanded-p)
(macroexpand-1 form env)
`(values ',expansion ',expanded-p))) => EXPAND-1
;; 単純なグローバル環境の実行例
(macroexpand-1 '(alpha a b)) => (BETA A B), true
(expand-1 (alpha a b)) => (BETA A B), true
(macroexpand '(alpha a b)) => (GAMMA A B), true
(expand (alpha a b)) => (GAMMA A B), true
(macroexpand-1 'not-a-macro) => NOT-A-MACRO, false
(expand-1 not-a-macro) => NOT-A-MACRO, false
(macroexpand '(not-a-macro a b)) => (NOT-A-MACRO A B), false
(expand (not-a-macro a b)) => (NOT-A-MACRO A B), false
;; レキシカル環境の実行例
(macrolet ((alpha (x y) `(delta ,x ,y)))
(macroexpand-1 '(alpha a b))) => (BETA A B), true
(macrolet ((alpha (x y) `(delta ,x ,y)))
(expand-1 (alpha a b))) => (DELTA A B), true
(macrolet ((alpha (x y) `(delta ,x ,y)))
(macroexpand '(alpha a b))) => (GAMMA A B), true
(macrolet ((alpha (x y) `(delta ,x ,y)))
(expand (alpha a b))) => (GAMMA A B), true
(macrolet ((beta (x y) `(epsilon ,x ,y)))
(expand (alpha a b))) => (EPSILON A B), true
(let ((x (list 1 2 3)))
(symbol-macrolet ((a (first x)))
(expand a))) => (FIRST X), true
(let ((x (list 1 2 3)))
(symbol-macrolet ((a (first x)))
(macroexpand 'a))) => A, false
(symbol-macrolet ((b (alpha x y)))
(expand-1 b)) => (ALPHA X Y), true
(symbol-macrolet ((b (alpha x y)))
(expand b)) => (GAMMA X Y), true
(symbol-macrolet ((b (alpha x y))
(a b))
(expand-1 a)) => B, true
(symbol-macrolet ((b (alpha x y))
(a b))
(expand a)) => (GAMMA X Y), true
;; シャドウの例
(flet ((beta (x y) (+ x y)))
(expand (alpha a b))) => (BETA A B), true
(macrolet ((alpha (x y) `(delta ,x ,y)))
(flet ((alpha (x y) (+ x y)))
(expand (alpha a b)))) => (ALPHA A B), false
(let ((x (list 1 2 3)))
(symbol-macrolet ((a (first x)))
(let ((a x))
(expand a)))) => A, false
defmacro
,
(setf
macro-function
),
macrolet
,
symbol-macrolet
なし。
*macroexpand-hook*
,
defmacro
,
(setf
macro-function
),
macrolet
,
symbol-macrolet
,
3.1. 評価
macroexpand
とmacroexpand-1
のどちらも、
マクロフォーム内にあるサブフォームのformやマクロを
明に展開するようなことはしません。
しかしそのような展開は
意味解析や実装のマクロ展開によって
暗黙的に行われることがあります。