マクロツイーター

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

\theナントカ で算術演算する話(3)

前回の続き)
「出力命令」が上手くいく方法

次の手順に従うと「悩ましいカウンタ出力命令」を正常に動作させることができる。

  1. まずは、「数値を出力に変換する」マクロを(脆弱でも何でもよいので)作る。すなわち、\format@hoge{hogeの数値の十進表記} を実行すると“hoge の出力”が得られるような \format@hoge を作る。(つまり、\format@hoge{42} を実行すると“43.”となるべき。)
  2. そのマクロ \format@hoge を保護付にする。つまり、\def(や \newcommand)の代わりに \DeclareRobustCommand で定義をする。(あるいは e-TeX 拡張の \protected を使う。)
  3. \thehoge を以下のように定義する。
    \def\thehoge{\expandafter\format@hoge\expandafter{\number\c@hoge}}

この手順に従って \thehoge を実装すると次のようになる。

\DeclareRobustCommand*\format@hoge[1]{%
  \count@=#1\relax \advance\count@1
  \number\count@ .}
\def\thehoge{\expandafter\format@hoge\expandafter{\number\c@hoge}}

\protected を利用する場合のコードも示しておく。

\protected\def\format@hoge#1{%
  \count@=#1\relax \advance\count@1
  \number\count@ .}
\def\thehoge{\expandafter\format@hoge\expandafter{\number\c@hoge}}

この実装が先述の「上手くいく条件」を満たしていることを確かめてみよう。ここで、\thehoge を 2 回展開すると \format@hoge{hogeの数値} が得られることに注意する。

  1. \thehoge を実行すると \format@hoge{42} を経て所望の“43.”が出力されるので OK。
  2. \thehoge の保護付完全展開は \format@hoge{42} であり、“hoge の数値”の情報が現れているので OK。
  3. \format@hoge{42} を実行すると“43.”が出力され、この時には hoge は参照されていないので OK。
補足

先に示した \format@hoge の実装では引数の数値を「\count@=#1\relax」のように参照しているため、引数としては「42」のような十進数字のみでなく「整数を表す任意のトークン列」を受け付けることができる。*1この場合は \thehoge の定義は単純に次のようにできる。

\def\thehoge{\format@hoge{\number\c@hoge}}

つまり「先に引数を数字列に展開しておく」必要が無くなるのである。\expandafter が 2 つも消えて気分爽快である。

アレを作ってみる

最後に、「上手くいく」手順を使って、元々の問題を解決してみよう。

\documentclass[a4paper]{article}
\newcounter{piyo}
\newcounter{hoge}[piyo]
\makeatletter %!!!!!!!!!!!!!!! TeX code BEGIN
\DeclareRobustCommand*\format@hoge[2]{%
  \count@=#1\relax \advance\count@1
  \number\count@.\number#2\relax}
\def\thehoge{%
  \format@hoge{\number\c@piyo}{\number\c@hoge}}
\makeatother  %!!!!!!!!!!!!!!! TeX code END
\begin{document}
hoge = \ref{test} /
\refstepcounter{piyo}% piyo = 1
\refstepcounter{hoge}\label{test}% hoge = 1
hoge = \thehoge
\end{document}

(ところでこの実装でも \format@hoge の実装を工夫している。もし \thehoge で「引数の 2 つの整数を先に展開するために \expandafter しないといけない」となるとどんな惨状が待っているかを考えてみてほしい。)

*1:余談であるが、“整数”を引数にする命令(マクロ)を実装する際にはできるだけ「“整数”であれば何でも受け付ける」ようにするのが望ましいと私は考えている。