読者です 読者をやめる 読者になる 読者になる

0番染色体

科学は全世界を照らす光である

\relax の使い方 12連発

LaTeX TeX

今回は TeX & LaTeX Advent Calendar 2015 の2日目の記事として投稿しています.初日の昨日は ZR氏 でした.明日は p_typo氏 の予定です.

\relax はその名の通り「TeX をリラックスさせる」命令です [1] .もう少し具体的に言うと,\relax は「何もしない」命令です.そのため,(La)TeX のソース中の適当な箇所に \relax を書き込んでも,多くの場合何も起こりません.例えば

\relax ああ,\relax とても\relax 緊張\relax する.\relax

などと書いたとしても,まるで \relax など存在しないかのように「ああ,とても緊張する.」と出力されるだけです.

ここで初めて \relax の機能を知った方は「そんな命令が何の役に立つというのだ」と思われることでしょう.しかし,実際にはこれが大いに役立ちます.TeX 言語のコード中では \expandafter と並んでよく用いられているぐらいです(当社調べ).したがって,\relax は今年の Advent Calendar のテーマ「今さら人に聞けない "TeX" のキホン」にまさしく適合する話題です.

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

なお,本稿では「一般的な \relax の使用法」のみならず「\relax である必然性はないが,しばしば \relax が用いられる事例」や「絶対にこういう使い方をすべきでない」ものまでリストアップしています.こうした注意はその都度指摘していきますが,読者諸氏におかれましても,すべてを鵜呑みにすることのないよう注意してお読みいただければと思います.

1. パッケージの衝突回避

LaTeX2e で新しい命令を作成するときは,一般に \newcommand 命令を用います.

\newcommand〈制御綴〉[〈引数個数〉]{〈定義〉}

このように「命令の定義」を行って以降ソース中に〈制御綴〉が現れると,当該〈制御綴〉は〈定義〉の内容に置き換えられます(このことを「展開」と呼びます).〈引数個数〉は定義する命令がとる引数の数を整数(0-9)で指定するものですが,引数を必要としない命令では省略可能です.〈定義〉中に #1, #2, #3,… のような「シャープ記号+整数n」という形が現れると,それぞれ「n番目の引数」に置き換えられます.

TeX の新規マクロ作成命令である \def も上記と似た書式(後述)をもちますが,\def は〈制御綴〉の内容が何であれマクロの定義を強行するのに対し,\newcommand は〈制御綴〉が「定義済み」の場合にはエラーを吐いて停止します.そのため,たまたま PackageA と PackageB の双方で \hoge が \newcommand を用いて定義されているときに,これらのパッケージを同時に読み込もうとするとうまくいきません(PackageB の \hoge 定義箇所でエラーとなります).

\usepackage{PackageA}
\usepackage{PackageB}  % => エラーになる

しかし,PackageA と PackageB の読み込みの間で,制御綴の代入を行う TeX の命令である \let *1 を用いて \hoge に \relax を代入してやると,エラーを回避することができます [2].

\usepackage{PackageA}
\let\hoge=\relax
\usepackage{PackageB}  % => エラーにならない

このように \relax を用いると,簡単にパッケージの衝突を回避することができます *2

ところで,どうしてこれで衝突を回避できるのかというと,“\relax を代入した \hoge” は \newcommand に「未定義の命令である」と判定されたからです.しかし,ここで注意して欲しいのは “\relax を代入した \hoge” は実際には「未定義」ではないということです.\hoge は \relax であると「定義」されています.このあたりの詳しい話は本稿の 8. の節ですることにします.

2. 引数の省略可能な命令の作成

LaTeX の命令書式としてはちょっと変わったものですが,次のような命令を作成することを考えます.

\Name{{Dazai}{Osamu}}% 「OsamuDazai」を出力\Name{{Akutagawa}}% 「Akutagawa」を出力

ひとまず,上記の1行目の挙動を実現する命令を定義してみます.

\newcommand\ABtoBA[2]{#2#1}
\newcommand\Name[1]{\ABtoBA#1}

簡単な命令なので,ほとんど説明は不要かもしれませんが,念のためこの命令の動作を細かく記述しておきます.

\Name{{Dazai}{Osamu}}」
->「\ABtoBA{Dazai}{Osamu}% \Name の〈定義〉における #1 が {Dazai}{Osamu} に置き換わったものになる
->「OsamuDazai」             % \ABtoBA の〈定義〉における #1 が Dazai,#2 が Osamu に置き換わる

ところで,この命令をそのまま2行目の例に適用すると,次のようになってうまくいきません.

\Name{{Akutagawa}}」
->「\ABtoBA{Akutagawa}% \Name の〈定義〉における #1 が {Akutagawa} に置き換わったものになる
->「」Akutagawa              % \ABtoBA の〈定義〉における #1 が Akutagawa,#2 が 」 に置き換わる

こうなった原因は,鍵括弧の閉じ(」)が \ABtoBA の2つ目の引数になってしまったことにあります.こういう場合にも \relax が役立ちます.\Name の定義を次のように変更します.

\newcommand\ABtoBA[2]{#2#1}
\newcommand\Name[1]{\ABtoBA#1\relax}

すると,さきほどはうまくいかなかった「苗字のみ」のケースでもうまく動作するようになります.

\Name{{Akutagawa}}」
->「\ABtoBA{Akutagawa}\relax% \Name の〈定義〉における #1 が {Akutagawa} に置き換わったものになる
->「\relax Akutagawa」         % \ABtoBA の〈定義〉における #1 が Akutagawa,#2 が \relax に置き換わる
                               % (\relax の後ろの空白は実際には存在しないが,見やすいように挿入した)
->「Akutagawa」                % \relax は何もしない

この \Name 命令自体には実用性の欠片もありませんが(書式が変わっている上,苗字と名前の間に空白を出力しないのも問題です),\relax を用いると「引数を省略可能な命令」を作ることが可能であることはおわかりいただけたと思います.

3. 可変命令のダミー

この項目からしばらくは,どうしても TeX 言語要素が絡んでしまうので,ここで TeX 式のマクロ作成命令 \def の使い方について説明します.といっても,\newcommand とあまり違いはありません.(本稿を読む上で把握しておくべき)主な違いは次の2点です.

  • 既に命令済みの命令でも,お構いなしに定義を上書きする
  • 引数の個数を数値で指定するのではなく,必要な数だけ #1#2#3… を書き並べる(最大 #9 まで)書式をとる

具体的な書式を以下に示しておきます.

\def〈制御綴〉#1#2#3{〈定義〉}

さて,\def は「定義済みの命令の定義を上書き」することができるので,この性質を利用すれば,ある1つの制御綴を「場所によって “意味” を変えて利用する」ことができます.こうした使い方をする際にも,\relax が役立つ場合があります.具体的な例を示してみましょう *3

【入力】

\def\TeacherComming{\let\Binge=\relax}
\def\TeacherGone{\def\Binge{ではなく,どんちゃん騒ぎ}}
\def\ClassRoom{生徒たちは勉強\Binge しています.}

\TeacherComming
1. \ClassRoom

\TeacherGone
2. \ClassRoom

【出力】

1. 生徒たちは勉強しています.
2. 生徒たちは勉強ではなく,どんちゃん騒ぎしています.

このように,ある制御綴(ここでは \Binge)に \relax を代入することで,その命令を一時的に無効化(あるいはその逆)することができるわけです.

4. 数値に後置する

TeX はプログラミング言語なので,条件分岐を行うための命令がいくつか存在しています.ここでは,その中で最も “普通” と思われる命令 \ifnum を紹介しておきます.\ifnum は数値の大小関係(もしくは等号)による条件分岐を実現するもので,基本的には以下のような使われ方をします.

\ifnum〈条件式〉〈条件式が真の場合の処理〉\else〈条件式が偽の場合の処理〉\fi

ここで〈条件式〉には 1<25=5 のような “普通の” 式が入ります.

では,さっそく \ifnum を用いて次のようなマクロ \case を作成してみます.

\def\case#1#2{\ifnum5>#1#2(事例#1\else 事例を紹介しすぎです!\fi}

上記マクロは第一引数(#1)が5より小さな数字かどうかを判定し,真であれば第二引数(#2)を表示,偽であれば「事例を紹介しすぎです!」と表示するように組んだ “つもり” です.正しく動作するか,試してみます.

【入力】

\def\case#1#2{\ifnum5>#1#2(事例#1\else 事例を紹介しすぎです!\fi}
\case{1}{TeXのおかげでバラ色の人生です}\\
\case{2}{20年以上LaTeXを使用していますが,いまとても幸せです}

【出力】

TeX のおかげでバラ色の人生です(事例1)
事例を紹介しすぎです!

この例で,私は事例1と事例2を紹介しようとしたわけですが,事例2の方は(2は5より小さな数であるにも関わらず)「事例を紹介しすぎです!」と怒られてしまいました.

こうなった理由はそう難しくありません.落ち着いてマクロ展開の様子を考えてみます.

\case{2}{20年以上LaTeXを使用していますが,いまとても幸せです}
-> \ifnum5>220年以上LaTeXを使用していますが,いまとても幸せです(事例2)\else 事例を紹介しすぎです!\fi
-> 事例を紹介しすぎです!

ご覧のとおり,第一引数は2だったわけですが,第二引数が「20」という数値から始まっているために,\ifnum の判定する条件式が 5>220 という意図せぬものになってしまっています.

これを防ぐためには,\case の〈定義〉の中で条件式の後ろに \relax を置くのが最も簡便です.

【入力】

\def\case#1#2{\ifnum5>#1\relax#2(事例#1\else 事例を紹介しすぎです!\fi}
\case{1}{TeXのおかげでバラ色の人生です}\\
\case{2}{20年以上LaTeXを使用していますが,いまとても幸せです}

【出力】

TeX のおかげでバラ色の人生です(事例1)
20年以上 LaTeX を使用していますが,いまとても幸せです(事例2)

このように,TeX で数値を扱うとき,特にその後ろにどのような文字列がくるかわからない場合には \relax を後置しておくと安心です.

5. 単位に後置する

TeX では,数値以外にも \relax を後置すべきものがあります.「単位」です.単位といっても大学生などがよく落とすアレではありません.「長さの単位」です.TeX で利用できる単位は色々ありますが,ここでは中でもよく使われるであろう pt を例に説明します.

TeX には好きな長さの(横方向の)空白を空けられる \hskip という命令があります.使い方は簡単で,\hskip のあとに好きな長さを書くだけです.たとえば,2.5pt の空白をあけたいときは次のようにします.

\hskip2.5pt

ところで,\hskip にはもっと高度な仕事をさせることも可能です.すなわち,空ける空白の長さだけでなく,許容する伸長度や縮小度を指定することができます.たとえば

\hskip5.5pt plus.5pt minus.5pt

のような指定をした場合(TeX では0.5を .5 のように省略して書くことができる)「基本的には 5.5pt の空白を作るが,状況によって 5.0pt から 6.0pt の間までであれば空白の長さを伸び縮みさせてもよい」という意味になります(私の理解では).

ここで,次のようなマクロを作ると危険であることは,既に 4. のくだりをお読み頂いた読者諸氏ならば簡単に気づかれることと思います.

\def\littleskip{\hskip2.0pt}

当然,\littleskip のあとにどのような文字列がくるかわからないので,たまたま plusminus といった文字列が続き,意図せぬ動作を引き起こす可能性があります.今度も,マクロ定義の末尾に \relax を置いておけばこうした事態を防ぐことができます.

\def\littleskip{\hskip2.0pt\relax}

このように単位の後ろにも,\relax を置いておいた方がいいことがあることは是非覚えておいてください.

6. 条件分岐命令に前置する

TeX には整数値を保存したり,簡単な演算を行ったりすることのできるカウンタレジスタというものが存在します.カウンタレジスタについては某愛好会のページなどに詳しい説明があるので,ここでは必要最低限の知識として以下の3つのことだけ指摘しておきます.

  • \newcount\foo でカウンタレジスタ \foo を定義できる(初期値は0)
  • \foo=〈数値〉 でカウンタレジスタ \foo に数値を代入できる(等号は省略可)
  • カウンタレジスタを \ifnum の〈条件式〉で使用することができる

さて,ではさっそく〈条件式〉にカウンタレジスタが登場する次のような TeX コードを考えてみましょう.

\newcount\foo
\foo=2\ifnum\foo>1 true\else false\fi

一応このコードで「しようとしたこと」を述べておくと次のようになります.

  1. カウンタレジスタ \foo を宣言する(このとき \foo の値は0になる)
  2. カウンタレジスタ \foo に 2 を代入する
  3. カウンタレジスタ \foo の値 2 は 1 より大きいので “true” が出力される

しかし,実際に上記のコードを TeX で処理すると “false” が出力されます.

このようになってしまう理由は些か複雑ですが,あえて平易に説明すると「TeX は何か探しものをしていると,はやとちりしがちになる」性質が原因にあります.つまり,上記の例では「\foo に 2 が代入されたことに気づく前に,条件の判定を行ってしまっている」というコトが起きてしまっているわけです.こうした場合には,いったん TeX を落ち着かせることが重要です.当然,\relax を使います.

\newcount\foo
\foo=2\relax\ifnum\foo>1 true\else false\fi

これで,期待通り “true” の出力が得られます *4

さきほど見たような「期待せぬ結果」は \ifnum 以外の条件分岐命令でも生じ得ます.特に,LaTeX 用のマクロを書く人にとっては重要であろう分岐命令 \ifmmode(数式モードか否かで条件分岐)ではこのような問題が発生しやすいので \relax を前置する癖をつけておいた方がよいでしょう.

条件判定に失敗する理由(TeX 沼!注意!)

さきほどの「TeX がはやとちりしがちになる」という説明は少々いい加減だったので,もう少し真面目に説明してみます.一度ここで「失敗するコード」を再掲します.

\newcount\foo
\foo=2\ifnum\foo>1 true\else false\fi

このコードを TeX が処理する際,2行目の \foo=2 まで読んだあと,TeX はさらに続く “数字” がないかを探します(ここで 1 がみつかれば当然 21 が \foo に代入されます).すると,TeX は \foo=2 の後ろに \ifnum があるのを見つけ「後続するのは “数字” ではない」ことを把握するわけですが,\ifnum を見てしまった TeX はその場で〈条件式〉の評価を行ってしまいます.ここで,この時点ではまだ \foo に 2 が代入されていないので,\foo の値は 0 のままであり,TeX は「偽」の判定を出してしまうわけです.

\ifnum の前に \relax を前置すれば,TeX は \relax を読んだときに \foo=2 の後ろが数値でないことを把握して代入操作を完了し,その後 \ifnum の評価に移るのでこのような問題は発生しません *5

7. 行末の空白挿入防止

まず「空白」に関する TeX の基本的な規則を3つほど確認しておきます.

  • TeX は基本的に「改行」も「空白」と同等に扱う *6
  • 制御綴の後の空白は(いくつならべても)無視される
  • 行頭の空白は(いくつならべても)無視される

その上で,次の TeX コードを考えます.

【入力】

\def\macro{
  \textsf{M}
  \textrm{acro}
}
This is it (\macro).

【出力】

This is it ( M acro )

上記マクロの作者は “Macro” の “M” だけ強調したかったわけですが,あちこちに余計な空白が入ってしまっています.理由は既に皆さんお気付きの通り \macro の〈定義〉に存在する「改行」です.こうした事態を防ぐためによくとられる手段は「行末をコメントアウト」してしまうというものです.

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

もちろん(この例では)これで何の問題もなく「変な空白の出力されない」よいマクロ *7 になるわけですが,さきほどの「空白」に関する3規則を思い出すと,\relax を用いた別の手も考えられます.

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

こちらは,行末をコメントアウトする代わりに「制御綴後の空白(改行)は無視される」ことを利用して空白の挿入を防いでいます(\relax は「何もしない」のでそれ以外の悪影響も一切ありません).

いずれの方法を用いても大抵の場合は特に変わりがなく,基本的にはコメントアウトする方法が広く用いられています(おそらく % を書く方が \relax を書くよりも楽だからでしょう).しかし,稀にコメントアウトではなく \relax を用いなければならないケースがあります.

ここで想定されているのは,次のような状況です.

\newcount\bar
\def\MyMacro#1{%
  \bar=#1[ココに何を置くかが問題]
  \hoge\fuga\piyo}

カウンタレジスタには “直接書き込まれた数字” でなくても,別のカウンタレジスタ(その値が代入される)などでも代入が可能なので,#1 の内容がどうなるかわかりません.こうした場合には,ZR氏のツイートに書かれている理由によりコメントアウトによる改行防止術は利用できないので,\relax を使用する必要があります(因みに \tw@ というのは常に 2 が代入された状態にあるカウンタレジスタです).

8. 対話モードの第一声

皆さんは TeX を対話モードで利用したことがあるでしょうか.「ない」という人のために念のため TeX を対話モードで起動する方法を確認しておきます.といっても,これは非常に簡単でコマンドライン *8 で tex と打って Enter を押すだけです(当たり前ですが TeX がインストールされている必要があります).

以上を私の環境(Mac OS X, TeX Live 2015)で実行すると,次のような入力待ち画面になります.

$ tex
This is TeX, Version 3.14159265 (TeX Live 2015) (preloaded format=tex)
**

ここで,この状態からできることは次の2つです.

  1. ファイル名を入力する:当該ファイルが読み込まれる
  2. 何らかの制御綴を入力する:そのまま対話的に TeX を使用する

対話モードで TeX を使いたい場合には,当然このうちの 2. に進みたいわけですが,最初に「したいこと」が制御綴の入力であるとは限りません.例えば,文書の冒頭に “Hello” と入れたい場合を考えます.TeX で “Hello” という文字列を出力(DVI や PDF に印字)したいときには,もちろんそのまま Hello と書けばいいわけですが,上の画面でそれを実行すると,TeX は「Hello.tex を読み込め」という意味に解釈してしまいます.これを防ぐため,対話モードで TeX を使いたいときは,最初はとりあえず \relax を入力するということがよく行われます *9

$ tex
This is TeX, Version 3.14159265 (TeX Live 2015) (preloaded format=tex)
**\relax

*

すると,最初は ** だったプロンプトが * に変化しています.この状態になれば,どんな文字列を入力してもファイル名として TeX に認識されてしまうことはないので,例えば Hello と入力すれば「“Hello” という文字列を出力せよ」というように TeX が解釈してくれます.これで,以降は楽しく TeX と会話することができます.

9. 未定義命令の判定

本節と次の 10. 節は,そこそこ TeX 沼度の高い話になるので,厳しければ読み飛ばして頂いても構いません.

一般に,TeX において「命令」(制御綴)はバックスラッシュを頭において \hoge と記述しますが,実は別の方法で表現することが可能です.その別の方法を実現する手段(の1つ)が \csname と \endcsname を用いるもので *10 これらの命令に挟まれた文字列は制御綴になります.すなわち,次の2行は等価です.

\TeX
\csname TeX\endcsname

ここで,\csname には「ただ制御綴を作る」だけではない興味深い性質があります.それは作った制御綴が「未定義」であった場合に,当該制御綴に \relax を代入するという性質です.すなわち,\undefined という制御綴が未定義であるとき(単に \undefined と書けば当然エラーになるわけですが)\csname undefined\endcsname は \relax と等価になります.

ところで,TeX には2つの制御綴の “意味” を比較して条件分岐を行うことのできる \ifx という命令があります.ひとまず,具体的な例を紹介しておきます.

【入力】

\def\macroA{a}
\def\macroB{a}
\ifx\macroA\macroB true\else false\fi

【出力】

true

\macroA と \macroB は異なる制御綴ですが,“意味” は同じなので「真」と判定されていることがわかります.

さて,これまでの説明した内容を組み合わせると「未定義命令かどうかの判定」を行うことができます.すなわち,未定義かどうか判定したい制御綴 \macroC を \csname macroC\endcsname の形で記述したものと \relax を \ifx で判定することで,未定義命令かどうかの判定を行うことができます.ただし,「\ifx による判定を実施する前に \csname を動作させなければならない」都合上,\expandafter を1つ使う必要があります.

\expandafter\ifx\csname macroC\endcsname\relax 未定義\else 定義済み\fi

\newcommand 等の LaTeX 命令は内部的に \@ifundefined という命令を用いて「未定義命令」の判定を行っていますが,この \@ifundefined が上述の方法を用いて判定を行っています.そのため,厳密には \macroC が \relax と等価になるように「定義済み」の場合にも「未定義命令」として判定されます.実際には \ifx を用いて \macroC と,完全に未定義であることが保証されている制御綴 \@undefined(未定義であることが保証されていれば具体的な制御綴はなんでもよい)を比較した方が厳密な判定になるわけですが,実際にはそうなっていないため本稿 1. で紹介したような「未定義化」が可能となっています *11

話が逸れましたが,\relax を用いると「未定義命令かどうかのおおまかな判定」ができるということがこの節で述べたかったことです.

10. 〈詰め物〉としての利用

『TeX ブック』によると,いくつかの変数に対する特定の状況では「代入式の “等号” の右側,“代入するもの” の左側」に \relax を置いてもいいものがあるようです [1].その変数とは「ボックス」と「トークン変数」の2種類で,要するに次のように書いても \relax は無視されるだけです.

【入力】

\setbox0=\relax\hbox{A}
\box0
\newtoks\mytoksA
\newtoks\mytoksB
\mytoksA={hoge}
\mytoksB=\relax\mytoksA
\the\mytoksA
\the\mytoksB

【出力】

A
hogehoge

ここで \relax を置けるとどのような利点があるのか現時点で私には理解できていないのですが(もしわかるかたがいらっしゃいましたら,是非教えて下さい),少なくともカウンタレジスタで同様のことをしようとするとエラーになるので,特筆に値する性質であることは確かです.

11. 文字列として出力

LaTeX で文書を作成中,紙面に “\relax” という文字列を出力したいと思ったとき(たとえば本稿のような文章を LaTeX で組もうとしているとき)はどうすればいいでしょうか.もちろん,バックスラッシュ(\)を出力する命令(\textbackslash など)に “relax” と続けて書くのも1つの手ですが,\relax を用いるともっと簡単に出力することができます.

TeX には後続の制御綴をそのまま「文字列」として出力することのできる \string 命令というものがあります.これと \relax を組み合わせることによって “\relax” という文字列を出力することができます.

\string\relax

あるいは「入力通りに表示させる」LaTeX の命令である \verb と組み合わせるという手も考えられます.

\verb|\relax|

いずれにせよ,\relax を用いると “\relax” という文字列を簡単に出力することができます.スゴいですね!

12. マクロとして使う

一般に,\relax は「制御綴」です.当然,\def を用いれば定義を上書きして様々な意味をもつマクロとして利用することができます *12

【入力】

\bgroup
\def\relax{進捗ありません}

「進捗どうですか」

「\relax\egroup

【出力】

「進捗どうですか」
「進捗ありません」

なお,あたりまえですが \relax の定義をこのように変更して利用することはまったく推奨されません.これまで散々紹介してきたように,\relax は非常に便利な命令で,様々なマクロの定義中で大量に利用されています.そのような命令の定義を勝手に書き換えれば「大惨事」が起こることは容易に推測できるはずです.実際,上記の例を次のようにすると,まったくおかしなことになってしまいます.

【入力】

\bgroup
\def\relax{進捗ありません}

「進捗どうですか」\\\relax\egroup

【出力】

「進捗どうですか」進捗ありません進捗ありません進捗ありません
「進捗ありません」

強制改行を表すマクロ \\ には \relax が少なくとも3度使用されているようです.兎にも角にも,\relax の定義を変更することは絶対に避けるべきです.

おわりに

以上 \relax の12通りの使い方を駆け足で説明してきました.私の思いつく限りの用法を網羅したつもりですが,まだ他にも様々な使い方ができるのかもしれません(ご存知もしくは思いついたという方はぜひコメントや Twitter で教えてください).

中には(私の説明下手のせいもあって)いくつかの用法は「難しい」と感じた方もいらっしゃるかもしれませんが,最低限「\relax という命令は,動作は単純だが実に様々な使い方があって,極めて有用な命令である」ということが伝わっていれば私としてはひとまずの目的を達成できたと言えそうです.

それでも,\relax は「何もしない」ごく単純な命令です.そのような命令 “だからこそ” このようにたくさんの用法が存在し得るのか,あるいはそのような命令 “でさえも” このように多くの使い方が可能なのか,今の私には判断しかねますが,いずれにせよこのことは TeX という言語の奥深さや面白さをよく物語っていることのように思えます.

TeX 言語の話はさておき,LaTeX ユーザがちょっとしたマクロを書く際にも,\relax が必要となる場面に遭遇する確率は決して低くありません.そういった場合も臆することなく,\relax をうまく使って “よい” マクロを書くよう心掛けていただければと思います.

\relax and enjoy TeXing!!

<参考文献>

[1] Knuth, Donald E. TeXブック. 鷺谷好輝 訳. 改訂新板, アスキー, 1994, 658p.
[2] 藤田眞作. LaTeX2eマクロ作法. 初版, ピアソン桐原, 2010, 652p.
[3] ページ・エンタープライズ. LaTeX2e【マクロ&クラス】プログラミング基礎解説. 初版, ページ・エンター プライズ, 2002, 417p.

*1:これも,\def と同様に定義済みの命令の定義を上書きできます.

*2:ただし,単純にこの方法を用いると PackageA の \hoge 命令は利用できないことになります.PackageA の \hoge 命令も利用したい場合には,\hoge に \relax を代入する前に,\hoge を同じく \let を用いて別の制御綴に代入するなどするとよいでしょう.

*3:以降の出力例では,インデントの設定は無効にされている(\parindent=0pt)ように表記しています.

*4:数値の後に \relax がきているので「数値に後置する \relax」のようにも見えますが,この場合に後ろにくる文字列は「数値ではない」ことがはっきりしているので,それでは説明がつきません.

*5:ただし,こうした説明は多く \ifmmode とアラインメントの組み合わせを例に行われます.というのは,今回のようなカウンタレジスタへの(数値トークンによる)代入直後の \ifnum 分岐の場合は,\relax を入れるよりも改行や空白で対処してしまうことが多いからだと思われます.

*6:ただし,日本語を扱う場合などは必ずしもこの限りではありません.

*7:当然のことながら,このマクロが一般的な意味で「よい / すばらしい」マクロという意味ではありません.

*8:Windows ユーザーで「コマンドラインがわからん」という人は「今さら聞けない!コマンドプロンプトの使い方」などを読むといいのではないでしょうか.

*9:既に述べたように,制御綴であればファイル名と解釈されることはないので,最初に「したいこと」がマクロ定義である場合などは,いきなり \def から入力を始めても実際には問題ありません.

*10:\csname の “cs” は control sequence の頭文字と思われます.

*11:\@undefine は通常「未定義」ですが,誰かがどこかでこれを「定義」してしまった瞬間に「未定義」でなくなってしまうということを考えると「完全に未定義であることが保証する」ということは(そういう TeX エンジンを実装しない限りは)原理上不可能です.これも LaTeX が未定義命令判定に \@undefined を用いた \ifx 判定を採用しなかった理由のひとつなのかもしれません(これは憶測にすぎません).

*12:ここで,\bgroup と \egroup は変更した \relax の定義が \egroup よりも後ろに影響を及ぼさないようにしています.

広告を非表示にする