| ホーム >> | LaTeX >> | マクロ >> | \\futurelet |
TeXには\futureletというプリミティブがある。 ここではこの\futureletの使い方について紹介する。
\futureletというプリミティブを『LaTeX2eマクロ&クラスプログラミング基礎解説』[1]を読んで知ったが、当初何の役に立つのかさっぱり分からなかった。 いくつか文献を読み、使い方も分かってきたので、メモとして残しておく。
\futureletはその後ろに3つのトークンを従えて、
\futurelet〈トークン1〉〈トークン2〉〈トークン3〉のように使う。 この時、これらは、
\let〈トークン1〉=〈トークン3〉〈トークン2〉〈トークン3〉
と同じ働きをする。 これだけでは何のメリットがあるのか分かりにくいが、 〈トークン2〉を実行する前に、〈トークン3〉を〈トークン1〉に代入しているところが味噌。 〈トークン2〉がマクロだとしてその中で〈トークン1〉が使われているならば、後置されている〈トークン3〉を〈トークン2〉の中で利用できることになる。
\futureletの具体的な働きを見てみる。 サンプルは文献[1]から引用する。 マクロ\@testは次のように定義されているとする。
\def\@test{[\@nexttoken]}
今のところ\@nexttokenには値が入っていないので、これだけで実行しても意味がない。 次に、\futureletを用いたマクロ\testを次のように定義する。
\def\test{\futurelet\@nexttoken\@test}
\futureletは3つのトークンを従えますが、ここでは2つだけしかない。
そして、次のマクロを実行する。
\test\LaTeX\futureletの3つめのトークンがここでは\LaTeXになる。 マクロの展開順を確認すると、
\test\LaTeX →\futurelet\@nexttoken\@test\LaTeX →\let\@nexttoken=\LaTeX\@test\LaTeX →\let\@nexttoken=\LaTeX[\@nexttoken]\LaTeX →[\LaTeX]\LaTeX
となる。 つまり、あるマクロ\testの動作が後置されたトークン\LaTeXによって変化する。
上記具体例を見てもどのような場合に使えるのか、これを使ってどんなメリットがあるのか見えてこないかもしれない。 TUGboat[2]に載っていたより実践的な例を紹介する。
あるマクロ\xxは、省略可能なオプションoptと、省略できない引数argをとることができるとする。
\xx[opt]{arg}
オプションを省略するときは、[opt]をまるごと省略して \xx{arg}と書くことができるとする。
このようなマクロを実現するためには、オプションが付いているかどうかを判定してそれによってマクロの動作を変える必要がある。 \xxに後置されているトークンを見て動作を変えるというのは\futureletの機能そのもの。
あらかじめオプションがついている場合に実行するマクロ\xxWithOptionと、付いていない場合に実行するマクロ\xxNoOptionを定義しておく。
\def\xxWithOption [#1]#2{ ..省略.. }
\def\xxNoOption #1{ ..省略.. }
マクロ\xxは\futureletを用いて次のように定義する。
\def\xx{\futurelet\@nexttoken\@xxDecide}
これで\xxの次にくるトークンを\@nexttokenに代入することができる。
あとは、後置のトークンが何かを判定して実行するマクロを変化させればよい。
判定は\ifxを使います。
\def\xxDecide {%
\ifx\@nexttoken [%
\let\next = \xxWithOption
\else
\let\next = \xxNoOption
\fi
\next
}
ここでは\ifxを使って\@nexttokenに大括弧"["が入っているかどうかを確認してる。
もし\@nexttokenが"["ならば、\xxの後に大括弧が来ているのでオプション付きだと判定できる。
マクロの展開を順に追ってみる。
\xx[1]{2}
→\futurelet\@nexttoken\@xxDecide[1]{2}
→\let\@nexttoken=[\@xxDecide[1]{2}
→\let\@nexttoken=[\ifx\@nexttoken [%
\let\next = \xxWithOption
\else
\let\next = xxNoOption
\fi
\next[1]{2}
→\xxWithOption[1]{2}
文献[2]には\xxを実現するもう一つの例が示されている。 前の例では、オプションの有無で実行するマクロを\xxWithOptionと\xxNoOptionとに振り分けていたが、ここではオプションが有る場合は\xx[1]{2}→\@xx[1]{2}、オプション無しの場合は\xx{1}→\@xx[1]{1}のよう引数とオプションに同じものを指定したと解釈することにする。そうすればマクロは一つだけ準備すれば良い。
これを実現するマクロは、次の通り。
\def\xx{\DblArg{\@xx}}
\def\DblArg #1{%
\def\@DblArgTemp{#1}%
\futurelet\@DblArgTok\@DblArg
}
\def\@DblArg{%
\ifx \@DblArgTok [%
\let\@DblArgTempA=\@DblArgTemp
\else
\let\@DblArgTempA=\@DblArgB
\fi
\@DblArgTempA
}
\def\@DblArgB #1{\@DblArgTemp[#1]{#1}}
マクロの展開順を追ってみると、
\xx{1}
→\DblArg{\@xx}{1}
→\def\@DblArgTemp{\@xx}\futurelet\@DblArgTok\@DblArg{1}
→\def\@DblArgTemp{\@xx}\let\@DblArgTok={\@DblArg{1}
→\def\@DblArgTemp{\@xx}\@DblArgB{1}
→\def\@DblArgTemp{\@xx}\@DblArgTemp[1]{1}
→\@xx[1]{1}
となる。