マクロツイーター

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

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

前回の続き)

さて後半戦である。もう一度「例の記事」への参照を載せておこう。

7. 行末の空白挿入防止
こうした事態を防ぐためによくとられる手段は「行末をコメントアウト」してしまうというものです.
\def\macro{%
  \textsf{M}%
  \textrm{acro}%
}
もちろん(この例では)これで何の問題もなく「変な空白の出力されない」よいマクロ *7 になるわけですが,さきほどの「空白」に関する3規則を思い出すと,\relax を用いた別の手も考えられます.
\def\macro{\relax
  \textsf{M}\relax
  \textrm{acro}\relax
}
こちらは,行末をコメントアウトする代わりに「制御綴後の空白(改行)は無視される」ことを利用して空白の挿入を防いでいます(\relax は「何もしない」のでそれ以外の悪影響も一切ありません).
(例の記事)

コメントアウトでおk。(おしまい)

敢えて補足しておくと、少なくとも自分の感覚では、たとえ TeX 言語であってもここで \relax を使うことは考えられないと思う。つまり、「元々作りたいマクロ」が

\def\macro{\textsf{M}\textrm{acro}}

であって、

\def\macro{\relax\textsf{M}\relax\textrm{acro}\relax}

ではない(たとえ動作は同じでも)のだから、その「作りたいマクロ」が作られる方が自然だからである。(ちなみに、私自身はマクロを定義する時に、原則としては、たとえ無害であっても“余計なトークン”は入れるのを避ける。)

なお、例の記事の 7 ではまだ話が続くが、後半の話は見出しの「行末の空白挿入防止」とは全く関係がなく、整数の終結の問題(4 で扱ったもの)である。前にも述べたように、LaTeX では「引数を必ず括弧で囲む」ので終結が曖昧になる問題は起こらないのである。((もちろん、\bar=42\setcounter{bar}{42} は「同じ動作」ではない。念のため。))

\newcounter{bar}
\newcommand*{\MyMacro}[1]{% #1に整数をとる
  \setcounter{bar}{#1}% 括弧に囲われている
  %...処理...
}
%
\newcounter{foo} \setcounter{foo}{42}
\MyMacro{42}          %整数を数字で指定
\MyMacro{\value{foo}} %整数を別のカウンタで指定
8. 対話モードの第一声

LaTeX に「対話モード」という概念が存在するか否か、という疑問は措いておいて、とにかく実践上は、latex を引数無しで実行すると対話モードで起動できる。

>latex
This is pdfTeX, Version 3.14159265-2.6-1.40.16 (TeX Live 2015/W32TeX) (preloaded
 format=latex)
 restricted \write18 enabled.
**
対話モードで TeX を使いたい場合には,当然このうちの 2. に進みたいわけですが,最初に「したいこと」が制御綴の入力であるとは限りません.例えば,文書の冒頭に “Hello” と入れたい場合を考えます.TeX で “Hello” という文字列を出力(DVI や PDF に印字)したいときには,もちろんそのまま Hello と書けばいいわけですが,上の画面でそれを実行すると,TeX は「Hello.tex を読み込め」という意味に解釈してしまいます.
(例の記事)

確かに plain TeX ではそうなのであるが、今起動したのは LaTeX なので、入力ファイル名を入力するのでなければ、ここでは「LaTeX の文書ソースの先頭行」を入力する必要がある。ところが、ほとんど全ての場合に、「LaTeX の文書ソースの(コメント行でない((実は、「**」プロンプトでコメント行を入力することはできる。つまり、「%」から始まる行を入力するとそれはコメントと解釈される。)))先頭行」は \documentclass 命令であることは周知の事実である。稀に、\RequirePackage などの別のものである場合もあるが、とにかく先頭は確実に制御綴(\ で始まる命令)である。だから、LaTeX の対話モードでは、単に「自分が入力したい先頭の行」を書けばよいのである。(つまり \reナントカ は不要。)

**\documentclass[a4paper]{article}{}

※補足事項

ただし、実際に上の行から始めて LaTeX の実行を完了させると、出力される DVI ファイルが article.dvi という気味の悪いものになってしまう。これは、TeX エンジンの一般的な挙動として「一番初めに読み込まれたファイル名」からジョブ名(DVI のベース名にもなる)を決定するからである((なのでもちろん、最初に「\relax」と入力しても結果は変わらない。))。従って、実際に対話モードを使いたい場合は次のように引数に null を指定したほうがいいだろう。

>latex null

こうすると、エンジンは「TeX システム中にインストールされている(実質)空っぽのファイル」である null.tex を読んだ後、対話モードに入る。「入力ファイル」は既に指定された後なのでプロンプトは最初から「*」になっている。(つまり \reナントカ は不要。)ジョブ名は null なので出力ファイルは null.dvi となる。

9. 未定義命令の判定
\expandafter\ifx\csname macroC\endcsname\relax 未定義\else 定義済み\fi
(例の記事)

LaTeX でもやってみよう。例によって、条件分岐を行うので、ifthen パッケージを利用する。

% ifthen パッケージを読み込んで
\ifthenelse{\isundefined{\macroC}}{%
  未定義%
}{%
  定義済み%
}

えっ、\rela(略

※補足事項

現在の TeX on LaTeX においては次のような慣習になっている。

  • 普通の(つまり英字と @ だけからなる)名前の制御綴については、「未定義」と「\relax に等置」は別のものと見なされる。つまり、自分の管理(名前空間)の下にない制御綴の意味を(\csname の副作用などのせいで)未定義から \relaX に変えてしまうことは、他のパッケージの動作に悪影響を与える可能性があるので、迂闊に行ってはならない。
  • 奇妙な(前項以外の)名前の制御綴については、それにアクセスするために \csname〜\endcsname を用いるのが普通であるため、「未定義」と「\relax に等置」を同一視する。
  • (もちろん、自分の管理下にある非公開の制御綴については、自分の好きなように扱って構わない。)

これに従うと、「未定義の検査」の正しい方法は、例えば \hoge@hoge のような普通の名前の制御綴については

\ifx\hoge@hoge\@undefined (未定義)\fi

が正しく、また \hoge!hoge のような奇妙な名前の制御綴については

\expandafter\ifx\csname hoge!hoge\endcsname\relax (未定義)\fi

が正しいということになる。\ifthenelse の述語の \isundefined は普通の名前の制御綴を対象とするため、\relax に等置されたもの(\relax 自身も含む)は定義済と判定される。

ちなみに、LaTeX の内部マクロの \@ifundefined は「\csname の副作用」を持っているため、自分の管理下にない(普通の名前の)制御綴については使えないことになる。恐らく、このマクロ(および \@ifdefinable)の本来の目的は、次のように「何かの命令を定義する時に、それが既に定義済である場合に対処する」こと(つまり \newcommand\providecommand をちょっと柔軟にしたもの)なのだと、私は考えている。

\@ifundefined{somecmd}{% 未定義なら
  % 定義する
  \def\somecmd{...}
}{%else 定義済なら
  % 何か別のことをする
}
10. 〈詰め物〉としての利用
TeX ブック』によると,いくつかの変数に対する特定の状況では「代入式の “等号” の右側,“代入するもの” の左側」に \relax を置いてもいいものがあるようです [1].
(例の記事)

Lamport 本によると、そもそも \relax という命令が存在しないため、\relax をどこかに置いてもいいという文法は存在しない。(おしまい)

11. 文字列として出力

さて、これまで実質的に \relax の活躍の場が全然見いだせていないわけで、熱狂的な \relax ファンとしては忸怩たる思いが積み重なっているだろう。

\string\relax
(例の記事)

これはどうか…? 残念! \string はどう考えても LaTeX 命令ではない……。

\verb|\relax|
(例の記事)

おっ!! これは完璧に LaTeX のコードだ! つまり、LaTeX でも \relax プリミティブは「\relax」と出力するのに有用である!

……残念ながら違う。LaTeX\verb 命令の引数では「\ も含めて全ての文字が非特殊なものとして扱われる」と規定されている。これに従うと、引数にある「\relax」は、(この記事のテーマであるところの)\relax プリミティブのことではないことになる。

<TeX沼>

\verbTeX 言語での実装を知っているなら、話はもっと明らかだろう。\ のカテゴリコードが 12 に変わっているため、上のコードを読んだ時に、\relax という制御綴はそもそも出現しないのである。

</TeX沼>

12. マクロとして使う
兎にも角にも,\relax の定義を変更することは絶対に避けるべきです.
(例の記事)

TeX ですらコレなので、LaTeX\relax を再定義するなんて言わずもがな。(おしまい)

ちなみに、LaTeX\relax という命令を作ろうとすると、\newcommand\renewcommand\providecommand の何れを使ってもエラーが発生する。例の記事で述べられているように、\newcommand が「定義済チェック」を行う場合は、\relax に等置されている制御綴は普通は「未定義」と判断するのであるが、\relax という制御綴自体については特別に判定を行って禁止しているのである。

まとめ
Lamport氏「ほーら、やっぱり \relax なんて要らんかったんや!」

熱狂的な \relax ファンにとっては残念な結果になってしまった。

しかし肩を落としてはいけない。そもそも、TeX において \relax「動作のない命令」であった。そして「動作のない」がゆえに、それは非常に大切なものなのである。翻って、LaTeX においては \relax は「出番のない命令」であることが判った。しかし、ここで先と同じように考えてみよう。「出番のない」がゆえに、それは非情jに大切なものとは考えることはできないか。

そう、実際に、\relax が「出番のない命令」である事実は、LaTeX において大きな意味をもつのである。\relaxTeX のごく基本的な命令でまた非情によく使われるので、TeX 者の多くはその存在を当たり前のように感じている。従って、そういう TeX 者が LaTeX パッケージの命令の仕様を設計する際に、散漫な考えをすると「\relax が使えることを前提としてしまう」危険性が待ち構えている。つまりは、TeX 者は LaTeX の「出番のない命令」である \relax に常に細心の注意を払い続けることが求められるのである。

貴方が、その存在を忘れない限りは
ソレは、いつでも、
貴方のそばにいるのである。