\noexpand何もわからん・続編

マクロ設定

\def\A#1#2{#1 is #2}
\def\B{\BB\BB}
\def\BB{foo}
\def\C{bar}

前回の結果

\edef\hoge{\noexpand\B\C} % -> \def\hoge{\B bar}
\expandafter\A\hoge % -> \A\B bar -> \B is bar -> \BB\BB is bar -> foofoo is bar

出力:foofoo is bar

\edef\hoge{\noexpand\B\noexpand\B\C} % -> \def\hoge{\B\B bar}
\expandafter\A\hoge % -> \A\B\Bbar -> \B is \B bar -> \BB\BB is \BB\BB bar -> foofoo is foofoobar

出力:foofoo is bar

\edef\hoge{\noexpand{\B\B}\C} % -> \def\hoge{\B\B bar}?
\expandafter\A\hoge % -> \A\B\Bbar -> \B is \B bar -> \BB\BB is \BB\BB bar -> foofoo is foofoobar ?

出力:foofoofoofoo is bar

最後の出力結果を見て、1行目は

\def\hoge{{\B\B} bar}

なのではないかという仮説を立てました。それを検証します。

追加実験

\edef\hoge{\noexpand{\A\B}\C} %仮説では\def\hoge{{\A\B}bar}
\expandafter\A\hoge%仮説では\A\B is bar -> foo is i s bar

これを実行すると、\edef文中でエラーを吐きました。メッセージを見ると、

! Argument of \A has an extra }.

とあります。ということは、{}の中身は展開しようとしており、展開を制御されているのは{だけであることがわかります。\noexpandは直後の1トークンの展開を制御しているものだが、{の展開を制御することは{}囲いを崩さないというだけにすぎず、{}の中身を展開しないという効果までは持たない、ということが判明しました。確かに\expandafterのときに{}によるカタマリという概念が一切存在しないということを思い出すべきでした。

振り返る

前回仮説を立てるために使った例は

\edef\hoge{\noexpand{\B\B}\C}%{\BB\BB\B}\C -> {foofoo\B}\C -> {foofoo\BB\BB}\C -> {foofoofoofoo}\C -> {foofoofoofoo}barという展開により
%\def\hoge{{foofoofoofoo}bar}と同義
\expandafter\A\hoge % -> \A{foofoofoofoo}bar -> foofoofoofoo is bar

となり、出力結果に合います。

他にも、

\edef\hoge{\noexpand{\expandafter\A\B}\C} % -> \edef\hoge{{\A\BB\BB}bar} -> \edef\hoge{{foo is foo}bar}
\expandafter\A\hoge % -> \A{foo is foo}bar -> {foo is foo} is bar -> foo is foo is bar

出力: foo is foo is bar

となり、正しそうです。


展開制御は闇が深いんだなぁ


ぺりをだねぇ