npt-japanese

% Function MACROEXPAND, MACROEXPAND-1

UP


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

定義

macroexpandmacroexpand-1は、マクロを展開します。

もしformがマクロフォームであれば、 macroexpand-1は一度だけマクロフォームを呼び出して展開します。

macroexpandは、マクロフォームではなくなるまでformを繰り返し展開します。 実際にmacroexpandは、 macroexpand-1を第二返却値がnilになるまで 繰り返し呼び出します。

もしformがマクロフォームならば、 expansionはマクロ展開の結果であり、 expanded-ptrueです。 それ以外のときは、expansionは与えられたformそのものであり、 expanded-pfalseです。

マクロ展開は次のようにして行われます。

macroexpand-1は、formがマクロフォームであると決定すると、 適用可能なマクロかシンボルマクロの展開関数を取得します。 *macroexpand-hook*の値は関数であることを強制し、 3つの引数を持つ関数として呼び出しを行います。 引数は展開関数とformenvです。 この呼び出しによって得られた値は、formの展開として受け取ります。

グローバル環境下のマクロ定義に加えて、 env内に定義されている macroletsymbol-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. 評価

備考

macroexpandmacroexpand-1のどちらも、 マクロフォーム内にあるサブフォームのformやマクロを 明に展開するようなことはしません。 しかしそのような展開は 意味解析や実装のマクロ展開によって 暗黙的に行われることがあります。


TOP, Github