マクロツイーター

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

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

expl3 における「展開制御支援」

このように完全展開の概念を 2 つに分ける理由は、expl3 の言語のもつ「展開制御支援」の機能にある。

1 つのトークン列を引数にとる関数(マクロ)があったとする。命名規則に従えば、そのような関数の引数指定子(argument specifier)は「n」となるので、関数名は :n で終わるはずである。いま関数名を \xx_some_fun:n とする。この時、標準モジュールの関数 \exp_args:〜 を用いて次のようなことができる。

  • \exp_args:Nx \xx_some_fun:n {<引数>} : 引数を網羅展開してできるトークン列を \xx_some_fun:n に渡す。
  • \exp_args:Nf \xx_some_fun:n {<引数>} : 引数を完全展開してできるトークン列を \xx_some_fun:n に渡す。

例を挙げて説明する。標準関数の \tl_show:n{<引数>} は、\show のように一旦停止して引数のトークンの内容をそのまま画面に出力する。(正体は e-TeX\showtokens プリミティブ。)例えば

\tl_show:n { A B \prg_do_nothing: { C } \scan_stop: }

を実行すると、画面に以下のように表示される。(expl3 の環境ではソース中の空白文字は無視されることに注意。)

> AB\prg_do_nothing: {C}\scan_stop: .
<*> ... { A B \prg_do_nothing: { C } \scan_stop: }

?

それでは、この \tl_show:n を使って、\exp_args:〜 の実験をしてみよう。

\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
% トークン列変数 \zrxx_foo_tl、\zrxx_bar_tl を用意し、
% \zrxx_foo_tl を 2 回展開すると文字列「FOO」、
% \zrxx_bar_tl を 1 回展開すると文字列「BAR」に
% 展開されるようにする。
\tl_new:N \zrxx_foo_tl
\tl_new:N \zrxx_foo_i_tl
\tl_new:N \zrxx_bar_tl
\tl_set:Nn \zrxx_foo_tl { \zrxx_foo_i_tl }
\tl_set:Nn \zrxx_foo_i_tl { FOO }
\tl_set:Nn \zrxx_bar_tl { BAR }
% 単純に \tl_show:n を呼び出す。何も展開されないはず。
\tl_show:n { \zrxx_foo_tl / \zrxx_bar_tl }
% \exp_args:Nf を付ける。完全展開されるはず。
\exp_args:Nf \tl_show:n { \zrxx_foo_tl / \zrxx_bar_tl }
% \exp_args:Nx を付ける。網羅展開されるはず。
\exp_args:Nx \tl_show:n { \zrxx_foo_tl / \zrxx_bar_tl }
\ExplSyntaxOff
\begin{document}% もはや本文は無意味
\end{document}

これを latexコンパイルすると、画面に以下のように表示される。

> \zrxx_foo_tl /\zrxx_bar_tl .        % 展開されない
…(中略)…
?                                       % Enter空打ち
> FOO/\zrxx_bar_tl .                  % 完全展開形
…(中略)…
?                                       % Enter空打ち
> FOO/BAR.                            % 網羅展開形
…(中略)…
? x                                     % x で終了

実は、ある関数の展開型を変えるために、\cs_generate_variant:Nn というもっと便利なものがあって、

\cs_generate_variant:Nn \tl_show:n { f }
%→ \tl_show:f が「\exp_args:Nf \tl_show:n」と同値になる
\cs_generate_variant:Nn \tl_show:n { x }
%→ \tl_show:x が「\exp_args:Nx \tl_show:n」と同値になる

のようなこともできる。