qa:56526 から始まる「付録の中にいるかの判定」についての話。
ある「解」が「正解」であるかは、当然「問題の立て方」に依存する。もし例えば
「article/report のそれと同じ意味をもつ\appendix
命令を有する」任意の文書クラスにおいて、「現在付録の中にあるのか(\appendix
が呼ばれた後か)」を判定せよ
というのであれば、そもそも \@chapapp
という内部マクロ自体が存在しない可能性があるので((article 系は「章(chapter)」が存在しないので、\@chapapp
はないであろう。report/book 系に限ったとしても、\@chapapp
は LaTeX のカーネル(latex.ltx)でなく各文書クラスで定義されているものだから、結局存在を保証できない。))、このマクロを使って何かするという解法は全て不正解である。*1これに対して、例えば状況が次のように「限定」されているとする。
\@chapapp
マクロは文書クラス内で次のように定義される。
\def\@chapapp{\chaptername}
\appendix
命令は\@chapapp
マクロを次のように再定義する。
\def\@chapapp{\appendixname}
\@chapapp
の定義がこれ以外の方法で(パッケージやユーザにより)変更されることはないと仮定する。\chaptername
と\appendixname
は再定義され得るが、両者が(1 回展開形において)同じにはならないと仮定する。*2
この仮定の下では、
\expandafter\ifx\@chapapp\appendixname
は「付録の中(\appendix
の後)であるか」の判定として完全な「正解」となる。それは以下の理由による。
\expandafter
を展開すると、(\@chapapp
が展開されて)以下の形になる。
\ifx〈\@chapapp の1回展開のトークン列〉\appendixname
- 「
\appendix
の後 ⇒ 真」の理由: この場合、「\@chapapp
の 1 回展開」は「\appendixname
」なので、展開は「\ifx\appendixname\appendixname
」となり、これは真と判定される。 - 「
\appendix
の前 ⇒ 偽」の理由: この場合、「\@chapapp
の 1 回展開」は「\chaptername
」なので、展開は「\ifx\chaptername\appendixname
」となる。仮定 4 より、この判定は確実に偽となる。((無引数マクロについて、1 回展開が異なれば必ず\ifx
は偽となるが、1 回展開が同じでも真になるとは限らないことに注意。\long
、\outer
といったマクロ属性があるためである。))
ところで、LaTeX 標準の report クラスにおいて、先の仮定の 1〜2 (3、4 は外的要因である)が成立するのかというと、実は微妙にそうなっていない。report.cls での \@chapapp
の定義は
\newcommand{\@chapapp}{\chaptername}
であり、これは TeX 式に書くと以下と同じになる。
\long\def\@chapapp{\chaptername}
つまり、マクロに \long
属性がついている。しかし何故か、\appendix
での再定義では \long
なしの \def
であり((実際は \gdef
だけど、\global
はマクロの属性ではないので無関係。))、再定義の前後で \@chapapp
の \long
属性が変わるという妙なことになっている(jsbook クラスでも全く同じ)。\long
は \ifx
の判定に影響するので、このことは無視できない事実であるが、しかし少し考えると、\@chapapp
自体を \ifx
の比較対象としてはいないので、結果的に同じ議論により、これらの場合でも上述の \ifx
による比較が正当であることが示される。
さて、私からもこの件に関して 1 つ出題することにする。((ただし、私自身は、別にフラグ(スイッチ)を用意して、\appendix
のところで立てる処理を行うのが適切だと考えているので、これは飽くまでも「問題のための問題」である。))
上述の「仮定」について、1〜3 は成立するが、4 は必ずしも成立しないという状況を仮定する。この「弱い仮定」の下で、\@chapapp
の定義をみて(つまり\appendix
の場所では他の処理を加えることなく)「\appendix
の前か後か」を判定するにはどうすればよいか?
4 が成立せず \chaptername
と \appendixname
が同じである場合は、\edef
で完全に展開すると区別が付かなくなり失敗することに注意。
TeX 言語を学習している人の大半は何か他の言語を既に心得ているものだと思われるが、トークンの展開制御というものは TeX 特有の概念でそう簡単には身につかないのが普通だと思う。*3でも実は、展開制御をマスターしてしまうと、もはや TeX の実行制御での難所はクリアできたともいえる。「トークン列の展開のイメージ」が掴めれば、とにかく自分の書いたプログラムの実行制御が正しいかを判断することができる。勿論、TeX の「組版の機能」を習得するのはまた別の話になるが…。