マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

expl3な言語で完全展開可能な関数(マクロ)を作る件について (2)

[追記 21:12]前にこれを書いていたこをすっかり忘れてた。なのでタイトル変更。

さて、TeX 言語での「完全展開可能」の話が済んだので、expl3 についての話を始めよう。以前に述べたように、expl3 の言語では「完全展開可能」を 2 つの細分している。

expl3 の言語における「完全展開可能」の定義

先日述べた「TeX 言語での定義」を再掲する。(ただし 1 つ条件を追加した。)


当該のマクロ \Macro について、以下の事項が(人為的に)決められているとする:

  • どういう引数が「正しい」のか?
  • 「正しい引数」の各々について、\Macro にそれが伴った場合の「正しい結果」のトークン列は何か?

    (※ただし、「正しい結果」のトークン列は「展開可能なトークン」を含まないものとする。)

この前提のもとで、\Macro に「正しい引数」が伴った任意のトークン列 S について、S を完全展開して生成されるトークン列 T が S に対する「正しい結果」と一致する。

その上で、expl3 の 2 つの「展開可能」は以下のように定義される。


  • 「完全展開可能(fully expandable)」: 上の定義中の「完全展開」を「(expl3 での意味の)完全展開」に置き換えたもの。
  • 「制限付展開可能(restricted expandable)」: 上の定義中の「完全展開」を「網羅展開」に置き換えたもの。
  • 「網羅展開(exhaustive expansion)」:「(TeX での意味の)完全展開」と同じ。従って、「制限付展開可能」は「(TeX での意味の)完全展開可能」と同義となる。

あと残っているのは、「(expl3 での意味の)完全展開(full expansion)」の定義だけである。expl3 で「トークン列を完全展開する」とは以下の操作を意味する。


トークン列の先頭にあるトークンが展開可能なものである間、それを展開することを反復する。

(以降、expl3 の用語に合わせる。)

この用語の使い方は expl3 で導入されたものであるが、2 つの「展開可能」の区別自体は従来の TeX 言語のマクロにも適用できる。*1例えば、先日の記事で例として挙げた(制限付展開可能な)\xx@is@empty が完全展開可能かを調べてみる。空トークン列を引数に与えたものを完全展開するとどうなるか。

  \xx@is@empty {}\ifx \xx@uniq \xx@uniq T\else F\fi
→T\else F\fi  〔if-分岐進入〕

網羅展開の場合と異なり、先頭が展開不能な文字トークンになっているので、完全展開はここで止まってしまう。従って、これは完全展開可能の条件を満たさない。

この場合、完全展開可能にするには例えば T/F の前に \expandafter を置くとよい。

\def\xx@is@empty#1{%
  \ifx \xx@uniq#1\xx@uniq \expandafterT%
  \else \expandafterF\fi
}

これで、先頭トークンの展開を繰り返すだけで「正しい結果」に至ることができる。(\expandafter が「展開」される時には、結果的に後方で展開が起こることになるが、展開されたのは飽くまで \expandafter 自体である。)

  \xx@is@empty {}\ifx \xx@uniq \xx@uniq \expandafter T\else \expandafter F\fi
→\expandafter T\else F\fi  〔if-分岐進入〕
    〔\expandafter があるため「\else F\fi」が展開される〕
→T  〔if-分岐脱出〕

*1:expl3 の言語の「関数」は結局は「TeX 言語のマクロ」に過ぎないので当然である。