マクロツイーター

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

LaTeX 的 \relax の使い方 12連発(1)

ステマ

TeX & LaTeX Advent Calendar

2015/12/01 〜 2015/12/25
〜今さら人に聞けない、TeXのキホン〜

☃ TeX & LaTeX アドベントカレンダー 2015 ☃

*  *  *

素敵な記事が連日届けられている TeX & LaTeX Advent Calendar であるが、2 日目の記事はコレであった。

TeX 言語の一番のキホンともいえる \relax プリミティブについての素晴らしい解説記事なのであるが、チョット気になる言明もある。

TeX 言語? いやいや,私は普通の LaTeX ユーザなので……」と思ったそこのあなた! このページを閉じるのはまだ早いです.本稿のすべての項目とは言いませんが,いくつかの項目は(TeX 言語を扱わない)一般の LaTeX ユーザでも知っておいて損のない話です.特に,今後「簡単かつ実用的なマクロ」を書く可能性のある人にとっては是非知っておいて欲しい内容と言えます.
(例の記事)

周知の通り、LaTeX には \relax という命令はない。そして、その理由が「Lamport 氏は \relax が不要になるように LaTeX の文法を設計したから」であることを知っている人もいるだろう。それを踏まえると、LaTeX において「\relax を知っておいて欲しい」場合がある、というのは、いわば Lamport 氏の設計に欠陥があることを主張するようなものであり、熱狂的な LaTeX ファンとしては聴き捨てならないものであることは間違いないだろう。

しかし例の記事は LaTeX に関する記述と TeX 言語に関する記述が入り混じっていて、「LaTeX\relax が有用である場面」というのが具体的にどこを指すのかがあまり明瞭ではない。そこで、例の記事と対照する形で、“LaTeX\relax したくなる時”が何であるかを検証することにした。それがこの記事の目的である。

※この記事では「LaTeX」はいわゆる「純 LaTeX(pure LaTeX)」、すなわち「LaTeX として規定された要素のみを含み、それ以外の TeX 言語要素を一切含まない言語」を指すものとする。「TeX 言語を一切知らない LaTeX ユーザ」が使うものは当然この「LaTeX」の範疇に収まるはずであろう。もちろん、これは LaTeX 文書中で「非 LaTeXTeX 言語」を用いることを非とするものではなく、また私自身はそういう立場をとる者ではないことを注意しておきたい。

1. パッケージの衝突回避
\usepackage{PackageA}
\let\hoge=\relax
\usepackage{PackageB}  % => エラーにならない
(例の記事)

このコードの中には TeX プリミティブの \let が使われている。当然、\letLaTeX 命令でないし、また敢えてそう見なすべきでも全然ない。だからここの話はそもそも LaTeX レベルのものではない。

「えっ、じゃあパッケージの衝突回避はどうすればよいの?」と思う人がいるかもしれないが、次の事を指摘しておきたい。

パッケージの衝突回避の処置を行うには
TeX 言語の知識が必要である

つまり「パッケージの衝突回避」自体が“TeX レベル”の行為なのである。

「完全攻略! LaTeX のマクロ定義」の記事で述べたように、LaTeX の範囲において、既存の(自分が定義したもの以外の)マクロの定義を変えてよいのは

「命令の定義が変更されることの影響」を完全に把握している状況
(「完全攻略! LaTeX のマクロ定義」)

に限られる。上掲の「パッケージの衝突回避」の処置において、PackageA 側から見ると、マクロ \foo の定義は、(元と互換性のないであろう)“PackageB の \fooの 定義”で置き換えられている。この事案が「『命令の定義が変更されることの影響』を完全に把握している状況」という条件を満たせるかというと、TeX 言語の知識を持っていない以上、それは無理であろう。唯一自明に「影響がない」といえるのは、「そもそも PackageA の機能を全く使っていない」場合であろうが、それだったら、初めから PackageA の読込を止めればよかったのである。これなら \let\relax も不要である。

\usepackage{PackageB}  % => 当然エラーにならない

※もちろん、非 TeX 言語者が LaTeX 文書を作るにあたって、「TeX 言語者が作成して提供した TeX コードを、その人が規定する仕様に従って使用する」(要するに「自分では全く TeX 言語コードを書かない」)ことに関しては、全く問題がないと私は考えている。「\let\foo=\relax で衝突が回避できる」という TeX 言語者の情報を得てそれを実行するのは、そういう事案の一種なのでやはり問題がない。

2. 引数の省略可能な命令の作成
\Name{{Akutagawa}}」
->「\ABtoBA{Akutagawa}\relax% \Name の〈定義〉における #1 が {Akutagawa} に置き換わったものになる
->「\relax Akutagawa」         % \ABtoBA の〈定義〉における #1 が Akutagawa,#2 が \relax に置き換わる
                               % (\relax の後ろの空白は実際には存在しないが,見やすいように挿入した)
->「Akutagawa」                % \relax は何もしない
(例の記事)

まあ、自分は「LaTeX で“引数指定が動的になる”マクロはあまり作るべきでない」と思っているが、それは措いておこう。

このケースでは、要するに“名”の部分を空文字列にすればよい。だから、空の括弧 {} を置くと期待通りの動作になる。

\newcommand\Name[1]{\ABtoBA#1{}}
\Name{{Dazai}{Osamu}}
→\ABtoBA{Osamu}{Dazai}{}
→OsamuDazai{}
⇒出力は“OsamuDazai”
\Name{{Akutagawa}}
→\ABtoBA{Akutagawa}{}
→Akutagawa
⇒出力は“Akutagawa”

※恐らく、“LaTeX のマクロ”として好ましいのは、\ABtoBA 自体を \Name の定義とすることであろう。つまり、初めから「\Name{Akutagawa}{}」のように指定させるわけである。

3. 可変命令のダミー
この項目からしばらくは,どうしても TeX 言語要素が絡んでしまうので,ここで TeX 式のマクロ作成命令 \def の使い方について説明します.
(例の記事)

ふむ、最初から LaTeX の話でないようだ。(おしまい)

ちなみに、その節の例にあるようなマクロは LaTeX でも一応実現できる。

\newcommand*{\Binge}{}
\newcommand*{\TeacherComming}{\renewcommand*{\Binge}{}}
\newcommand*{\TeacherGone}{\renewcommand*{\Binge}{ではなく,どんちゃん騒ぎ}}
\newcommand*{\ClassRoom}{生徒たちは勉強\Binge しています.}
4. 数値に後置する
TeXプログラミング言語なので,条件分岐を行うための命令がいくつか存在しています.
(例の記事)

LaTeXマークアップ言語なので、条件分岐のような“実行制御”は本来の目的ではない。しかし条件分岐は文書を作成する上でも何かと便利なので、LaTeX の“標準パッケージ群”*1(tools バンドル)の中には ifthen パッケージという条件分岐をサポートするためのパッケージが含まれている。

では,さっそく ifthen を用いてマクロ \case を作成してみよう。

% ifthen を読み込んで
\newcommand{\case}[2]{%
  \ifthenelse{5 > #1}{%
    #2(事例#1%
  }{%
    事例を紹介しすぎです!%
  }%
}
\case{1}{TeXのおかげでイバラの人生です}\\
\case{2}{20年以上LaTeXを使用していますが,いまとても辛いです}

え、\relax……? 何ソレ?

5. 単位に後置する
TeX には好きな長さの(横方向の)空白を空けられる \hskip という命令があります.
(例の記事)

LaTeX には好きな長さの(横方向の)空白を空けられる \hspace という命令がある。

\hspace{5.5pt plus.5pt minus.5pt}

ではさっそくこれを利用したマクロを作ってみよう。

\newcommand*{\littleskip}{\hspace{2.0pt}}
\noindent\littleskip Minuscule letters are ...

素晴らしい。

え、\relax……? 何ソレ?

※この例に限らず、LaTeX の命令では「引数は必ず括弧に入れる」規則になっているので、終端が曖昧になる事例が発生しない。

\baselineskip=10pt plus 4pt\relax % TeX
\setlength{\baselineskip}{10pt plus 4pt}% LaTeX
6. 条件分岐命令に前置する

うーむ…………。

やっぱり、ここで述べられていることは本質的に 4 の「数値に後置する」と同じであるような気がする。

TeX は \foo=2 の後ろに \ifnum があるのを見つけ「後続するのは “数字” ではない」ことを把握するわけですが
(例の記事)

どうもこの辺の記述がアヤシイ。

<TeX沼>

TeX の if文は展開可能であるので、整数を読み取る文脈で if 文が出現した場合、展開を行って数字トークンを探そうとする。そしてそれこそが「代入が起こる前に if 文の判定が起こる」原因なのである。

\count@=12\iftrue 3\else 4\fi 5
%=> \count@ に 1235 が代入される

“普通の LaTeX ユーザ”から見ると奇異に感じられるかも知れないが、例えば、if 文で OR 判定をするためのイディオムはこの性質を使っているので、“普通の TeX 言語者”であれば誰でも知っている常識であろう。

\ifnum0\if@foo 1\fi \if@bar 1\fi >0
  % スイッチ @foo と @bar の少なくとも一方が真の時に実行
\fi

</TeX沼>

そういうわけで、少なくとも 6 で詳しく述べられている事例に関しては、4 に属するものとみる方が妥当であろう。

*1:LaTeX の構成物の一部”として配布されているパッケージ群。これに対して、hyperref や geometry 等の他の大部分のパッケージは、第三者が作成したものである。