매크로 정의

같은 내용을 여러 번 반복해서 입력하거나, 나중에 한꺼번에 고치고 싶다면 자신만의 명령(매크로)을 정의합니다. 기본은 \newcommand입니다. 이 페이지에서는 인수 받기, 기존 명령 재정의, 현대적인 \NewDocumentCommand, 그리고 “fragile” 명령을 피하는 방법까지 직접 만든 명령의 기초를 살펴봅니다.

\newcommand로 명령 정의하기

가장 기본적인 도구는 \newcommand{\name}{definition} 입니다. 첫 번째 인수에는 만들 명령 이름, 두 번째 인수에는 그 내용을 씁니다. 연구 그룹 이름을 여러 번 쓴다면 프리앰블에서 한 번 정의해 두고, 본문에서는 \name만 입력하면 definition으로 전개됩니다.

latex
% プリアンブルで定義 / define in the preamble
\newcommand{\grp}{Knuth Typesetting Lab}

% 本文で使う / use it in the body
Welcome to the \grp. The \grp{} was founded in 1978.

두 번째 \grp 뒤에 붙은 {} 에 주목하세요. \grp처럼 문자만으로 된 명령은 바로 뒤 공백을 “명령 이름의 끝”으로 먹어 버립니다. 그래서 \grp was라고 쓰면 “Lab was”가 아니라 “Labwas”처럼 공백이 사라집니다. 표준 해결책은 빈 중괄호 {}를 두어 이름이 끝나는 위치를 표시하는 것입니다(자세한 내용은 “문법 규칙” 참조).

중요한 원칙은 \newcommand그 이름이 아직 정의되지 않았을 때만 성공한다는 것입니다. 이미 존재하는 명령 이름(LaTeX 커널이나 패키지 명령 포함)에 사용하면 Command \name already defined 오류로 멈춥니다. 기존 명령을 실수로 덮어쓰는 일을 막기 위한 의도적인 안전장치입니다. 기존 명령을 일부러 다시 만들려면 아래의 \renewcommand를 씁니다.

인수를 받는 매크로

호출할 때마다 내용을 바꾸고 싶다면 명령에 인수를 둡니다. \newcommand{\name}[⟨nargs⟩]{... #1 #2 ...} 처럼 명령 이름 뒤의 대괄호에 인수 개수 를 쓰고, 정의 안에서 #1, #2 등으로 참조합니다. 매개변수는 #1부터 #9까지, 최대 9개 입니다.

latex
\newcommand{\unit}[2]{#1\,\mathrm{#2}}

% \unit{9.8}{m/s^2} → 9.8 m/s^2(数と単位の間に細い空き)
$a = \unit{9.8}{m/s^2}$

첫 번째 인수를 선택 사항으로 만들고 기본값을 줄 수도 있습니다. \newcommand{\name}[⟨nargs⟩][⟨default⟩]{...} 처럼 대괄호를 두 번 겹치면 #1이 선택 인수가 되고, 그 기본값이 ⟨default⟩가 됩니다. 호출할 때는 \name(기본값 사용) 또는 \name[x](#1x로 설정)라고 씁니다. 남은 필수 인수는 #2부터입니다.

latex
% 全 2 引数、うち #1 は省略可能で既定値 2
\newcommand{\plusbinomial}[2][2]{(x + y)^{#1}_{#2}}

$\plusbinomial{n}$      % → (x + y)^2_n   (#1 は既定の 2)
$\plusbinomial[3]{n}$   % → (x + y)^3_n   (#1 を 3 に)

대괄호 개수 세는 법에 주의하세요. [⟨nargs⟩]⟨nargs⟩에는 선택 인수를 포함한 전체 인수 수 를 씁니다. 즉 위 예는 “인수 두 개, 그중 첫 번째가 선택”이라는 뜻입니다. 또한 [⟨default⟩]쓰지 않는 것 과 빈 대괄호 []를 쓰는 것은 다릅니다. 후자는 “기본값이 빈 문자열인 선택 인수”입니다.

재정의, 조건 정의, robust 만들기

\newcommand에는 목적이 다른 세 친척이 있습니다. 모두 인수 작성법([⟨nargs⟩][⟨default⟩])은 \newcommand와 같고, 차이는 이미 정의된 이름에 어떻게 동작하느냐입니다.

명령기존 이름에 대해주요 용도
\newcommand오류로 중단새 명령을 안전하게 만들기
\renewcommand덮어씀(정의되어 있지 않으면 오류)기존 명령 다시 만들기
\providecommand아무것도 하지 않음(기존 정의 유지)중복 로드될 수 있는 스타일 파일
\DeclareRobustCommand덮어쓰고 로그에 기록이동 인수에서 쓰는 robust 명령

\renewcommand 는 기존 명령을 다시 정의하는 명령입니다. \newcommand와 반대로 대상이 이미 정의되어 있지 않으면 오류 가 납니다. 예를 들어 목록의 첫 번째 단계 기호를 바꾸는 것처럼 LaTeX가 미리 제공하는 명령의 내용을 바꿀 때 씁니다.

latex
% itemize の第 1 階層の記号をダッシュに
\renewcommand{\labelitemi}{--}

% 既存マクロを新しい中身で作り直す
\renewcommand{\grp}{Lamport Typesetting Lab}

\providecommand 는 “아직 없을 때만 정의”하는 명령입니다. 이름이 정의되어 있지 않으면 \newcommand와 완전히 같고, 이미 정의되어 있으면 아무것도 하지 않고 기존 정의를 유지 합니다(오류도 없음). 여러 곳에서 읽힐 수 있는 스타일 파일에서 명령을 “혹시 몰라 제공”할 때 알맞습니다.

\DeclareRobustCommand 는 내부에 fragile 코드가 있어도 robust 명령 을 만듭니다(robust와 fragile의 뜻은 다음 절). \newcommand와 달리 기존 이름에 대해서도 오류가 나지 않고, 재정의하면 로그 파일에 기록 만 남깁니다. 다만 이렇게 만든 명령은 약간 비효율적이므로, 내용이 fragile이고 이동 인수에서 쓰이는 경우에만 사용하고, 그 밖에는 \newcommand를 권장합니다.

fragile 명령과 \protect

LaTeX에는 이동 인수(moving argument) 라는 특별한 문맥이 있습니다. \section{...}의 제목은 본문에 조판될 뿐 아니라 목차, 페이지 머리글, .aux 보조 파일에도 쓰여 여러 곳으로 “이동”합니다. \caption{...}(그림과 표 캡션), \thanks{...}, tabular/array@{...} 내용도 마찬가지입니다.

이런 문맥에서 전개되면 깨져서 잘못된 TeX 코드가 되는 명령을 fragile command, 문제없는 것을 robust command 라고 합니다. 고전적인 대처는 fragile 명령 바로 앞에 \protect 를 두어 “여기서는 전개하지 말고 그대로 써라”라고 지시하는 것입니다. 보호는 명령마다 필요하며, \protect는 바로 뒤의 하나만 보호합니다.

latex
% 可動引数の中で壊れやすい \verb を保護する
\section{The \protect\verb|\par| primitive}

다만 좋은 소식이 있습니다. 2019년 10월 LaTeX 이후, 예전에 fragile이던 많은 명령이 robust가 되었습니다. 선택 인수를 받는 \raisebox 같은 명령이나 인라인 수식 \(...\)도 이제 \protect 없이 제목에 쓸 수 있습니다. 그래도 대표적으로 남아 있는 것이 \verb 입니다. 이는 \protect로도 잘 해결되지 않는 경우가 많으므로, 제목이나 캡션에서는 \texttt{...}로 다시 쓰는 편이 빠릅니다. 직접 매크로를 만들 때는 \DeclareRobustCommand로 처음부터 robust하게 정의해 두면 \protect 걱정이 사라집니다.

현대적인 \NewDocumentCommand

현대 LaTeX에는 더 강력한 정의법인 \NewDocumentCommand{\name}{⟨arg-spec⟩}{...} 도 있습니다. 원래는 xparse 패키지 기능이었지만, 지금은 LaTeX 커널(ltcmd)에 포함 되어 \usepackage 없이 사용할 수 있습니다. 인수 개수를 숫자로 쓰는 대신, 인수 종류를 나열한 “인수 지정(arg-spec)” 으로 선언하는 것이 특징입니다.

지정자의미정의 안에서 받는 형태
m필수 인수(mandatory)보통의 #1 같은 인수
o선택 인수 [...]주어지지 않으면 “값 없음” 표시
O{default}기본값 있는 선택 인수주어지지 않으면 default
s별표 *의 유무\IfBooleanTF로 참거짓 판정

\newcommand보다 강력한 점은 두 가지입니다. 선택 인수를 여러 개 받을 수 있고, 별표형(starred) 변종을 정식으로 다룰 수 있습니다. 아래 예제는 별표 유무를 \IfBooleanTF로 분기합니다(여기서 #1은 별표, #2는 필수 인수). 새 코드에서는 이 현대적 인터페이스를 권장합니다. 자세한 내용은 “xparse” 페이지에서 다룹니다.

latex
\NewDocumentCommand{\diff}{s m}{%
  \IfBooleanTF{#1}%
    {\frac{\mathrm{d}}{\mathrm{d}#2}}%   星つき: d/dx 形
    {\mathrm{d}#2}%                      星なし: dx 形
}

$\diff{x}$    % → dx
$\diff*{x}$   % → d/dx

좋은 매크로 작성법

매크로가 가장 힘을 발휘하는 것은 의미 기반 매크로 입니다. 실수 전체를 \newcommand{\R}{\mathbb{R}}, 미분 d를 \newcommand{\dd}{\mathrm{d}}처럼 “무엇인가”에 이름을 붙여 두면 문서 전체의 표기가 통일되고, 나중에 글꼴을 바꾸고 싶어도 정의 한 줄만 고치면 모든 곳에 반영됩니다.

latex
\newcommand{\R}{\mathbb{R}}
\newcommand{\dd}{\mathrm{d}}

% 統一された表記で書ける / write with consistent notation
$\int_{\R} f(x)\,\dd x$

그렇다고 매크로를 너무 많이 만들면 읽기 어려워집니다. \newcommand{\x}{\xi} 같은 극단적인 축약은 몇 달 뒤의 자신이나 공동 저자에게 암호가 될 수 있습니다. 반복이 많거나, 나중에 일괄 변경하고 싶거나, 의미에 이름을 붙일 가치가 있는 것에 한정하고, 나머지는 그대로 쓰는 편이 결국 읽기 쉬운 경우가 많습니다.

마지막으로 이름 충돌을 피하세요. LaTeX 커널이나 패키지 명령을 \renewcommand로 가볍게 바꾸지 마세요. 뜻밖의 부작용이 날 수 있습니다. 직접 만든 명령에는 너무 짧은 이름을 피하고, 가능하면 프로젝트 고유의 접두사 를 붙이세요(\myR, \bookTitle 등). 그러면 기존 명령이나 다른 패키지와 부딪히기 어렵습니다. 헷갈리면 먼저 \newcommand로 정의해 보세요. already defined 오류가 나면 이미 쓰이는 이름입니다.