マクロツイーター

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

TeX芸人実力判定問題、その2(解答)

例の \en の問題の解答。

e-TeX 拡張エンジン上の plain TeX または LaTeX において、以下の要件を満たすように制御綴 \en を定義せよ。

  • \en は (La)TeX の寸法指定における「単位」の位置に書くことができる。
  • そして、「現在の 0.5em」の長さを表す。すなわち、1\en0.5em は常に同じ長さを表す。

補足条件:ただし、plain TeXLaTeX で既に定義済の制御綴の定義を変えてはいけない。

もちろん、次のものは不正解である。

\newdimen\en \en=0.5em

何故なら、これだと「em 値の解釈(絶対値への変換)」が \en に代入する時に起こってしまって、その後変わらないからである。だから、この後(fontdef トークンが実行されて)現在フォントが変わると、そこではもはや \en は「現在の 0.5em」とは一致しなくなる。((とすると、「\font プリミティブにフックを入れて……」という方向を考えたくなるかも知れないので、補足条件を入れてこちらを排除しておいた。))といって、

\def\en{0.5em}

という単純極まるマクロで定義すると、確かに \en はいつでも「現在の 0.5em」となるが、2\en は当然ながら \en の 2 倍ではなく 20.5em となるのでこれもダメである。

e-TeX 前提の出題であるが、必要な e-TeX の機能は、割と有名なアレである。すなわち、正解はコレ。

\def\en{\dimexpr 0.5em\relax}

これだけでよい。

\def\en{\dimexpr 0.5em\relax}
\font\cmttX=cmtt10 \cmttX
\skip2=-\en plus 1.23\en minus \en
\showthe\skip2 %==> -5.24994pt plus 6.4574pt minus 5.24994pt.

これでよい直接の理由は、\dimexpr の式は、その式の値に等しい「単位」として機能するからである。例えば、

\parindent=6\dimexpr3pt\relax %「\dimexpr3pt\relax」は「単位」となる

とすると、代入されるのは 18.0pt である。

なお、\relax\dimexpr の式の終端を表すのに使われる(値が解釈される際に吸収されその場には残らない)。もし \en の定義に \relax がないと、\dimen0=10\en+1pt のような場合に「+1pt」が巻き込まれてしまう(本来はそのまま文字として出力されるべき)ので不完全である。

何故 \dimexpr は「単位」になるのか

これは要するに「そういう仕様」なのであって、理由を挙げるのは難しい。ただし、以下の性質を考えて合わせていけば納得し易いかも知れない:

  • TeX では「数字で書いた値」と「そうでない値」(「内部値」という)では文法的な扱いが異なる。
    例えば、\count@=\p@ とすると \count@ には 1pt の換算値である 65536 が代入される。これに対して、値を直接記述して \count@=1pt とすると \count@ は 1 となり文字「pt」が出力される。明らかに挙動が違う。
  • 「単位」の役割を担える寸法は「内部値」のものだけである。
    つまり、「\p@」は単位になるが、「1pt」は単位にならない。((「pt」は純粋な単位で、それ自体は寸法ではない。))
  • \XXXexpr の式はそれ自体は展開可能でなく、前に \the を付けて初めて「その式の値(の数字表記)」に展開される:例えば、\edef\foo{\numexpr6*7} とした場合、\foo は「\numexpr6*7」のままである。\edef\foo{\the\numexpr6*7} とした場合は、\foo は「42」になる。
  • つまりは、\numexpr6*7 自体は数字で書いた「42」とは同等ではない。そして、\the というのは、「内部値」を「数字で書いた値」に変換する(例えば \the\p@1.0pt)プリミティブである。そう考えると、\XXXexpr の式はそれ自体は「内部値」と解釈できる。
  • 従って、\dimexpr の式は「内部値の寸法」なので「単位」として機能する。