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
(-1 (alpha a b)) => (BETA A B), true
(expandmacroexpand '(alpha a b)) => (GAMMA A B), true
(=> (GAMMA A B), true
(expand (alpha a b)) macroexpand-1 'not-a-macro) => NOT-A-MACRO, false
(-1 not-a-macro) => NOT-A-MACRO, false
(expandmacroexpand '(not-a-macro a b)) => (NOT-A-MACRO A B), false
(=> (NOT-A-MACRO A B), false
(expand (not-a-macro a b))
;; レキシカル環境の実行例
macrolet ((alpha (x y) `(delta ,x ,y)))
(macroexpand-1 '(alpha a b))) => (BETA A B), true
(macrolet ((alpha (x y) `(delta ,x ,y)))
(-1 (alpha a b))) => (DELTA A B), true
(expandmacrolet ((alpha (x y) `(delta ,x ,y)))
(macroexpand '(alpha a b))) => (GAMMA A B), true
(macrolet ((alpha (x y) `(delta ,x ,y)))
(=> (GAMMA A B), true
(expand (alpha a b))) macrolet ((beta (x y) `(epsilon ,x ,y)))
(=> (EPSILON A B), true
(expand (alpha a b))) let ((x (list 1 2 3)))
(symbol-macrolet ((a (first x)))
(=> (FIRST X), true
(expand a))) let ((x (list 1 2 3)))
(symbol-macrolet ((a (first x)))
(macroexpand 'a))) => A, false
(symbol-macrolet ((b (alpha x y)))
(-1 b)) => (ALPHA X Y), true
(expandsymbol-macrolet ((b (alpha x y)))
(=> (GAMMA X Y), true
(expand b)) symbol-macrolet ((b (alpha x y))
(
(a b))-1 a)) => B, true
(expandsymbol-macrolet ((b (alpha x y))
(
(a b))=> (GAMMA X Y), true
(expand a))
;; シャドウの例
flet ((beta (x y) (+ x y)))
(=> (BETA A B), true
(expand (alpha a b))) macrolet ((alpha (x y) `(delta ,x ,y)))
(flet ((alpha (x y) (+ x y)))
(=> (ALPHA A B), false
(expand (alpha a b)))) let ((x (list 1 2 3)))
(symbol-macrolet ((a (first x)))
(let ((a x))
(=> A, false (expand a))))
defmacro
, (setf
macro-function
), macrolet
, symbol-macrolet
なし。
*macroexpand-hook*
, defmacro
, (setf
macro-function
), macrolet
, symbol-macrolet
, 3.1. 評価
macroexpand
とmacroexpand-1
のどちらも、 マクロフォーム内にあるサブフォームのformやマクロを 明に展開するようなことはしません。 しかしそのような展開は 意味解析や実装のマクロ展開によって 暗黙的に行われることがあります。