LaTeX で自分だけのコマンド(マクロ)を定義する一番の理由は、打鍵数を減らすことではありません。ベクトルをすべて \mathbf{v} と書いた学位論文が四百箇所あって、指導教員が「やはり矢印にしてほしい」と言い出す場面を想像してください。\newcommand をひとつ用意して \vect{v} と書いてあったなら、変更はプリアンブルの一行で済みます。そうでなければ四百回の慎重な置換です。マクロとは、あとから考えを変えるための場所なのです。このページは \newcommand と引数の書き方から始めて、\renewcommand と \providecommand の違い、マクロの直後の空白が消える理由、壊れやすい命令と \protect、そして現代的な \NewDocumentCommand までを順に見ていきます。
\newcommand で自分のコマンドを作る
書き方は \newcommand{\name}{definition} の一行です。第 1 引数が作りたいコマンドの名前、第 2 引数がその中身で、以後 \name と打つたびに definition に置き換わります。置き場所はプリアンブル、つまり \begin{document} より前が定石です。ここで効いてくるのが冒頭のベクトルの話で、\vect という名前は 見た目ではなく意味 を指しています。「太字」と書く代わりに「これはベクトルだ」と書いておけば、太字にするか矢印を載せるかという判断は定義の側に一箇所だけ残る。これは LaTeX 自身の設計と同じ考えかたです——本文で 14pt の太字を直接指定せずに \section と書くのも、まったく同じ取引をしているからです。
% preamble: one line decides how every vector in the document looks
\usepackage{amsmath,amssymb}
\newcommand{\vect}[1]{\mathbf{#1}}
% \newcommand{\vect}[1]{\vec{#1}} % swap this line, the whole thesis follows
% semantic names for things you refer to constantly
\newcommand{\R}{\mathbb{R}}
\newcommand{\dd}{\mathrm{d}}
% body
\[ \vect{v} \cdot \vect{w} = \lvert \vect{v} \rvert \, \lvert \vect{w} \rvert \cos\theta \]
\[ \int_{\R} f(x) \, \dd x \]引数をとるマクロと、省略可能な引数
呼び出しごとに中身を変えたいなら、名前のうしろの角括弧に 引数の個数 を書き、定義の中では #1・#2 … で受け取ります。つまり \newcommand{\name}[⟨nargs⟩]{... #1 #2 ...} です。ここで上限がひとつあって、パラメータは #1 から #9 までの 9 個 しか使えません。おもしろいのは、10 個目を要求したときに返ってくる ! You already have nine parameters. というエラーが LaTeX ではなく TeX エンジンそのもの から出ることです。この制限は \newcommand の都合ではなく、その下で動く \def プリミティブの仕様で、LaTeX には緩める術がありません。9 個で足りなくなったら、たいていは引数ではなくキー・バリュー方式に設計を変えるべきだという合図です。
% two mandatory arguments: a number and a unit
\newcommand{\unit}[2]{#1\,\mathrm{#2}}
$a = \unit{9.8}{m/s^2}$さらに 最初の引数だけを省略可能にして既定値を与える ことができます。角括弧を二つ重ねた \newcommand{\name}[⟨nargs⟩][⟨default⟩]{...} がその形で、#1 がオプション引数になり、書かずに呼べば ⟨default⟩ が入ります。呼び出しは \name{...}(既定値を使う)か \name[x]{...}(#1 を x にする)で、残りの必須引数は #2 から数えます。ここで数え方に落とし穴があって、[⟨nargs⟩] には オプション引数も含めた総数 を書きます。下の例の [2][2] は「引数 2 個、うち先頭が省略可能で既定値は 2」という意味です。
% two arguments in total; the first is optional and defaults to 2
\newcommand{\pow}[2][2]{(x + y)^{#1}_{#2}}
$\pow{n}$ % -> (x + y)^2_n
$\pow[3]{n}$ % -> (x + y)^3_n
% starred form: the argument may not contain a blank line
\newcommand*{\keyword}[1]{\textsf{#1}}ふたつ細かい点を足しておきます。ひとつは、[⟨default⟩] を 書かない ことと空の括弧 [] を書くことは別物だということ。後者は「既定値が空文字列のオプション引数」になります。もうひとつは星付きの \newcommand* で、こちらは引数に空行(\par)を書けない「短い」マクロを作ります。ただの制限に見えますが実は診断機能で、閉じ括弧を忘れたときに ! Paragraph ended before \keyword was complete. が 間違えた場所の近くで 出てくれます。星なしだと TeX は次の段落もその次も引数だと思って読み進め、エラーは数ページ先で出ます。段落をまたぐはずのないマクロには * を付けておくのが親切です。
\newcommand・\renewcommand・\providecommand の違い
三つとも引数の書き方は同じで、違うのは すでに使われている名前に出会ったときの態度 だけです。\newcommand は拒否して止まり、\renewcommand は上書きし、\providecommand は黙って引き下がって既存の定義を残します。だから既存の名前に \newcommand を当てると ! LaTeX Error: Command \emph already defined. で停止し、逆に未定義の名前に \renewcommand を当てると ! LaTeX Error: Command \foo undefined. で停止します。この二つは対になっていて、うっかり潰す事故と、潰したつもりが何も潰していない事故 を両側から防いでいます。
ところで \newcommand{\endnotes}{...} と書くと、そんな名前のコマンドはどこにも存在しないのに Command \endnotes already defined. で止まります。エラーの二行目が種明かしをしていて、Or name \end... illegal, see p.192 of the manual. と続きます。latex.ltx の中の名前検査は、未定義であることを確かめたうえで さらに先頭三文字が end でないこと、そして名前が relax でないこと を要求するのです。\end{itemize} は内部的に \enditemize を呼ぶ仕組みなので、end で始まる名前を勝手に作られると環境の対応関係が壊れてしまう——だから接頭辞ごと予約されています。「定義済み」というエラー文言は、この二つ目の理由まで含めた大雑把な言い方です。
| 命令 | 既存の名前に対して | 主な用途 |
|---|---|---|
\newcommand | エラーで停止 | 新しい命令を安全に作る |
\renewcommand | 上書きする(未定義だとエラー) | 既存の命令を作り直す |
\providecommand | 何もしない(既存定義を残す) | 二重に読み込まれ得るスタイル |
\DeclareRobustCommand | 上書きし、ログに記録を残す | 可動引数で使う頑強な命令 |
実務での使い分けははっきりしています。\renewcommand は「LaTeX が既に用意しているものを差し替える」窓口で、箇条書きの記号を変える \renewcommand{\labelitemi}{--} はその典型です。\providecommand は「まだ無ければ用意する」宣言で、自分のスタイルファイルが他のファイルから二度読み込まれても事故らないようにするためにあります。下の例では \vect がすでにあるので \providecommand は 何もせず、太字の定義が生き残ります。そして \DeclareRobustCommand は次節の主役で、既存の名前に当てても止まらず、LaTeX Info: Redefining \emph on input line 2. のような一行を .log に残すだけです。黙って上書きするのではなく記録を残す——これが \renewcommand との実質的な違いです。
% replace something the class already defines
\renewcommand{\labelitemi}{--}
% define only if nobody else did; here \vect exists, so this line is a no-op
\providecommand{\vect}[1]{\vec{#1}}
% redefine on purpose, and say so in the log
\DeclareRobustCommand{\emph}[1]{\textbf{#1}}マクロの後ろの空白が消える理由と \xspace
英字だけでできたコマンド名は 最初の非英字で終わり、そのあとに続く空白は名前の区切りとして捨てられます。だから \newcommand{\lab}{Knuth Lab} を用意して本文に \lab was founded. と書くと、出力は「Knuth Labwas founded.」になります。空白が「消えた」のではなく、TeX が \lab という名前をどこで打ち切るか判断するために食べてしまったのです。おもしろいのは例外があること——\$ de はきちんと「$ de」と空きを保ちます。\$ は英字ではない一文字だけの制御綴りで、名前の終わりが一文字目で確定するため、うしろの空白を読む必要がないからです。つまりこの罠は 英字のコマンド名だけ に効きます。
\usepackage{xspace}
\newcommand{\lab}{Knuth Lab}
\newcommand{\labx}{Knuth Lab\xspace}
\lab was founded. % -> Knuth Labwas founded.
\lab{} was founded. % -> Knuth Lab was founded.
\lab\ was founded. % -> Knuth Lab was founded.
\labx was founded. % -> Knuth Lab was founded.
\labx, and a comma. % -> Knuth Lab, and a comma.直し方は三つあります。定石は空の中括弧 \lab{} で名前の終わりを明示すること、次に制御空白 \lab\ 、そして三つ目が xspace パッケージの \xspace です。\xspace の賢いところは、無条件に空きを入れるのではなく次のトークンを覗いてから決める ことにあります。xspace.sty の例外リストには , . ' / ? ; : ! ~ - ) と閉じ括弧、それに \footnote などが並んでいて、これらが続くときは空きを足しません。だから \labx, and は「Knuth Lab, and」と正しく組まれます。このパッケージは LaTeX の tools バンドルの一部で、原作者は David Carlisle です。必要なら \xspaceaddexceptions で例外を追加できます。ただし \xspace は先読みの技なので、引数をとるマクロ(どうせ } で終わる)には不要ですし、他のマクロの引数の中では思わぬ挙動をすることがあります。迷ったら {} がいちばん安全です。
壊れやすい命令、可動引数、\protect と \DeclareRobustCommand
自作マクロが節見出しやキャプションの中で突然壊れることがあります。原因は 可動引数(moving argument) です。\section{...} の文字列は本文に組まれるだけでなく、目次のために .aux 補助ファイルへ書き出され、ページ見出しにも回されます。つまり同じ内容が別の場所へ「移動」する。\caption{...}、\thanks{...}、tabular や array の @{...} も同じ性質を持ちます。書き出しの瞬間に展開されると意味を失うコードを含む命令を 壊れやすい命令(fragile command)、そのまま書き出されても平気なものを 頑強な命令(robust command) と呼びます。
古典的な対処が \protect で、壊れやすい命令の直前に置いて「ここでは展開せずそのまま書き出せ」と指示します。保護は一回に一命令ぶんだけです。ただし朗報があって、2019 年 10 月の LaTeX リリース以降、かつて壊れやすかった命令の多くが頑強になりました。この変更は LaTeX News 30 の「Making more user commands robust」の節に記録されていて、\begin と \end、つまり環境そのものまで見出しの中で使えるようになっています。それでも残る代表格が \verb で、節見出しに入れると ! LaTeX Error: \verb illegal in argument. で止まります(多くの場合 ! Paragraph ended before \@sect was complete. も道連れです)。ここは \protect では救えないので、見出しやキャプションでは \texttt{...} に書き換えるのが現実的です。
% \verb cannot go here at all -- rewrite it
\section{The \texttt{\textbackslash par} primitive}
% a macro that is robust from the start, even though \ifmmode is fragile
\DeclareRobustCommand{\seq}[2][n]{%
\ifmmode #2_{1}\ldots #2_{#1}\else\textbf{??}\fi
}
\section{Sequences $\seq{x}$} % works without \protect自分のマクロについては、\protect を毎回思い出すより \DeclareRobustCommand で最初から頑強に定義してしまうほうが確実です。引数の書き方は \newcommand と同じで、中身に \ifmmode のような壊れやすいコードが混じっていても、出来上がる命令は可動引数に耐えます。上の \seq は LaTeX の clsguide に載っている例で、まさにこれを示すために書かれたものです。代償はごくわずかな非効率なので、見出しやキャプションに登場する見込みのないマクロまで頑強にする必要はありません。判断の目安は「このマクロは目次に載る可能性があるか」の一点です。
\NewDocumentCommand — 現代的な定義の書き方
\newcommand は「角括弧のオプション引数を最大ひとつ、そのあとに必須引数」という形しか作れません。この制限を外すのが \NewDocumentCommand{\name}{⟨arg-spec⟩}{...} です。引数の個数を数字で書く代わりに、引数の種類を表す文字を並べた「引数指定(arg-spec)」 を渡します。もとは xparse パッケージの機能でしたが、2020 年 10 月 1 日のリリースで LaTeX カーネル(ltcmd)に取り込まれ、いまは \usepackage{xparse} なしで使えます。この移管は LaTeX News 32 に記録されています。
| 指定子 | 意味 | 定義内での受け取り |
|---|---|---|
m | 必須引数(mandatory) | 通常の #1 などの引数 |
o | 省略可能な [...] 引数 | 無いときは「値なし」の印 |
O{default} | 既定値つきのオプション引数 | 無いときは default が入る |
s | 星 * の有無 | \IfBooleanTF で真偽を判定 |
ここが \newcommand に対して決定的に有利な点です。オプション引数を複数とれる こと、そして 星付き(starred)の変種を正式に扱える こと。s を書いておくと #1 には星の有無が真偽値として入り、\IfBooleanTF{#1}{星あり}{星なし} で分岐できます。名前の頭に New/Renew/Provide/Declare を付け替えると、それぞれ \newcommand/\renewcommand/\providecommand/無条件上書きに対応します。新しく書くコードではこちらを既定にして構いません。ただし \newcommand は消えも古びもしていないので、引数がひとつふたつの短い定義なら従来どおりで十分です。
% s = optional star, m = mandatory argument
\NewDocumentCommand{\diff}{s m}{%
\IfBooleanTF{#1}%
{\frac{\mathrm{d}}{\mathrm{d}#2}}% starred: d/dx
{\mathrm{d}#2}% plain: dx
}
$\diff{x}$ % -> dx
$\diff*{x}$ % -> d/dx
% O{...} gives an optional argument with a default
\NewDocumentCommand{\note}{O{note} m}{\textbf{#1:} #2}マクロの名前の付け方と、定義を置く場所
名前の衝突を避ける一番の道具は、実は \newcommand そのものです。\renewcommand や \def で先に上書きしてしまうと何が起きたか分かりませんが、まず \newcommand で定義してみれば、already defined が出た時点で「その名前は誰かが使っている」と教えてくれます。だからこそ カーネルやパッケージの命令を \renewcommand で気軽に潰さない こと。自作の名前には短すぎるものを避け、プロジェクト固有の 接頭辞 を付けるのが安全です(\myR、\bookTitle など)。とくに \ker、\deg、\arg、\Re といった一・二文字の数学演算子名は既に使われているので、\R を使いたければ \newcommand で一度試して確かめる価値があります。
マクロは増やしすぎても読めなくなります。\newcommand{\x}{\xi} のような極端な省略は、数か月後の自分や共著者にとって暗号です。繰り返しが多い・後で一括変更したい・意味に名前を与えたい ものに絞り、それ以外は素直に書いたほうが結局読みやすい。判定は簡単で、「この名前は読んで意味が分かるか」——\vect は分かり、\x は分かりません。
最後に置き場所です。一本の論文ならプリアンブルで十分ですが、章ごとにファイルを分けた本や、同じ記法を使い回す複数の論文になると、定義だけを別ファイルに切り出して \usepackage で読み込むほうが管理しやすくなります。ここに小さな利点があって、.sty や .cls の中では @ が英字として扱われる ため、\makeatletter を書かなくても \mybook@vecfont のような内部名がそのまま使えます。@ を含む名前は文書本文からは呼べないので、外に見せる命令と内部だけの命令を名前で区別できる わけです。プリアンブルでこれをやるには \makeatletter と \makeatother で挟む必要があり、そのぶん事故のもとになります。
% ---- mynotation.sty --------------------------------------------
\ProvidesPackage{mynotation}[2024/01/01 shared notation]
\RequirePackage{amsmath,amssymb}
% private: the @ makes it uncallable from the document body
\newcommand{\mynot@vecfont}[1]{\mathbf{#1}}
% public
\newcommand{\vect}[1]{\mynot@vecfont{#1}}
\newcommand{\R}{\mathbb{R}}
% ---- thesis.tex ------------------------------------------------
% \usepackage{mynotation}