\markboth/rightは展開される

TeXにおいて分かりにくいものにマークの概念があります.マークの詳細には触れませんが,柱などに「何章」とか「何節」という本文の場所を示すものを出力するための機構だというくらいの理解でとりあえずは問題ないです.もっとも,以下の内容はマークというものが分かっていて,さらに複雑な柱や目次を作る必要のある人にしか意味がないですし,そういう人は職業的にTeXを扱っている人くらいかもしれません.けど,多分,分かってる人はそういうプロ的な人の中でもかなり少数派かもしれません.

このマークを作成するためにLaTeX2eが準備しているマクロに\markboth/\markrightというのがあります.

\markboth{left}{right}
\markright{right}

というように使います.もっともこれらのマクロはマクロの内部で使うもので,直接本文で使うことは推奨されません.leftが左(偶数ページ),rightが右(奇数ページ)に出力するものです.ここでこのようなコードを考えます.

\documentclass{jbook}
\begin{document}
\newdimen\A
\markright{\A=100pt\relax\the\A}
\end{document}

このとき,柱にはどのような文字列がでるでしょうか.もちろん,100ptです(勘違い)*1.実は 0pt です.では次はどうなるでしょうか.

\documentclass{jbook}
\begin{document}
\newdimen\A
\A=10pt\relax%%%%追加
\markright{\A=100pt\relax\the\A}
\end{document}

「\Aに100ptを代入して,それを表示するのだから「100pt」だろう」でしょうか.

実は違います.

「10pt」と表示されます.これは「マークは展開される」ということが原因です.\markrightが実行されたときに,その引数である

\A=100pt\relax\the\A

は展開されます.ここで,\A,=,100pt,\relaxはこれ以上展開できません.しかし,\the\Aは展開可能なのです.したがって,\markrightによって,作成されるマークの中身は

\A=100pt\relax10pt

となるのです.したがって,出力は「10pt」となります.つまり,\markrightの引数の中でいくら\Aの値を変えても無駄なわけです.マークとして作成されたものの中で出力に影響を与えるものに\Aは関与していないのです.

もう少し複雑な例を出します.

\documentclass{jbook}
\begin{document}
\newdimen\A
\A=10pt\relax%%%%追加
\markright{\A=100pt\ifdim\A<20pt SMALL\else LARGE\fi}
\end{document}

このとき,実際に出力されるのはLARGEかSMALLどちらでしょうか?

これはやはりSMALLです.マークには展開後のものが入るのでした.前述のように\A,=,100ptは展開されません.しかし,条件分岐は展開されます.したがって,\markrightが実行されたときには\Aは10ptなので\A<20ptは正です.つまり,SMALLの方だけが残ります.したがって,マークは

\A=100pt SMALL

となるのです.

このような展開はマークだけではなく,\writeも全く同じです.つまり,柱だけではなく目次の作成などにも影響がでます.このように展開して欲しくないのに展開してしまうというようなことを避けるには,適切に\protect/\noexpandや\DeclareRobustCommandなどを使って「展開の抑制」をしっかり意識する必要があります.

*1:まとめてる段階で嘘をかいてしまった・・・