TeX言語🤮でよくネタにされるものとして\expandafterや\aftergroupといった“変態的なプリミティブ”がある。今回のテーマである\futureletもその“変態的なプリミティブ”の一種として紹介されることが多い。
ところが実は\futureletは「その動作を理解するだけ」であればそんなに難しいものではない。特に「他人が書いた\futureletを含むコードの動作を把握したい」という場合は、\futureletの定義さえ知っていれば「とにかく定義に愚直に従って動作を把握する」ことができる。\futureletが“読める”ことはそれだけでも大きなメリットになるだろう。
そういうわけで、本記事では\futureletの動作を理解したうえで、その知識を使って実際に\futureletを“読む”ことを目標とする。
前提知識
とにかく \futurelet の規則を知ろう
\futureletの動作を把握するには「TeXのコードを“トークンの列”として見る」ことが大事である。\futureletが実行される場面において、実際に\futurelet以降のコードを“トークンの列”と考えてみよう。
\futurelet‹トークン1›‹トークン2›‹トークン3›‹トークン4›……
この前提の下で、「\futurelet‹トークン1›」という文は、以下の動作を行う。
注意として、(少なくとも本記事の定義では2)\futureletの“引数”に相当するのは‹トークン1›だけであるので、文を実行した後も‹トークン2›と‹トークン3›はそのまま残っている。従って、この文の次には‹トークン2›が実行されることになる。
補足
\futureletは代入文の一種である。従って、一般の代入文についての諸々の注意事項(\global修飾や\afterassignmentなど)は\futureletについても当てはまる。
とにかく \futurelet するコードを読もう
\futureletの規則を把握したので、次はその規則を使って\futureletを使った簡単なコードを“読む”練習をしてみよう。以下のコードにおいて、マクロ\Checkが何をするものなのかを言葉で説明してほしい。
\def\Check{\futurelet\my@tok\my@check@a} \let\my@bgroup={ %←暗黙文字トークン \def\my@check@a{% % \my@tokが'{'であるなら... \ifx\my@tok\my@bgroup \message{Yes}% \else \message{No}% \fi}
読んでみる
パッと見たところでは\Checkは引数を取らないようなので、\Check単体で展開を追ってみる。
\Check ↓(展開) \futurelet\my@tok\my@check@a
\futureletの規則を愚直に適用すると、\futurelet\my@tokが実行されるとその文の2つ先にあるトークンを見ることになるが、今考えている範囲では、文の後にあるトークンは1つしかない。結局、\Checkの直後に何かトークンがある状態を考える必要があったようである。\Checkの直後のトークンを‹トークンA›とする。
\Check‹トークンA›…
\Checkを展開すると以下のようになる。
\futurelet\my@tok\my@check@a‹トークンA›…
改めて\futureletの規則を適用すると、\futurelet\my@tokを実行すると、2つ先にある‹トークンA›が\my@tokに\letされる3。その後の入力バッファは以下のようになる。
\my@check@a‹トークンA›…
これ以降は\my@check@aの展開・実行となる。\my@check@aは単純なコードなので、以下の動作をすることは容易に理解できるであろう。
\my@tokの意味が(カテゴリコード1の){に等しいかを調べて、そうであればYes、なければNoを端末に出力する。
ここで\futureletの実行により「\my@tokの意味」は「‹トークンA›の意味」と等しくなっている。従って、\my@check@aは実質的には‹トークンA›の意味を調べていることになる。
これで\Checkのコードを完全に“読む”ことができた。結局、\Checkの動作を言葉で説明すると以下のようになる。
- 自身の直後にあるトークン(の意味)が(カテゴリコード1の)
{に等しいかを調べて、そうであればYes、なければNoを端末に出力する。
まとめ
もうこれで、読んでいるコードの中に\futureletが出てきてもコワくありません! どんどんTeX言語🤮のコードを読んでいきましょう💁