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

LaTeXでマクロの引数をオーバーロード

はじめに

TeX Forumにこんな質問が来ていた.

TeXにおける制御綴の引数の個数について

要は,TeXのマクロを関数っぽいものとみなし,その上で同名のマクロに引数の個数が異なるものをオーバーロードさせたいというものである.TeXのマクロは単なる字句の置き換え規則に過ぎない*1ので,これを実現するにはTeX言語沼に入らないといけない*2

先の記事の場合,要件は1引数および2引数の場合のみだったが,今後,複数の場合でオーバーロードしたい場合があるかもしれない.単に,そのようなマクロを定義するためのマクロをつくるのが面白そうなので作ってみた.

スタイルファイルの紹介

公開場所

今回,スタイルファイルをoverload.styとして,hak7a3 / overload — Bitbucketに公開しておいた.

使い方

overload.styの使い方は,非常に簡単である.まず,\usepackageでoverload.styを読み込む.

\usepackage{overload}

次に,\newoverloadでオーバーロードするコントロールシーケンスを登録する.

\newoverload{\foo}

ここでは,\fooを「これから複数の引数に対応するマクロ」として登録している.最後に,各引数の個数に対応する動作を\addoverloadで登録する.\addoverloadは\newoverloadで登録したコントロールシーケンス,引数の個数,およびマクロの置き換えテキストを引数として受け取り,オーバーロード用のマクロを作成する.

\addoverload{\foo}{2}{(2):#1 and #2}
\addoverload{\foo}{1}{(1):#1 only}
\addoverload{\foo}{0}{(0):orz}

この例では,上から順に2引数,1引数,および引数がない場合の動作を登録している*3

引数をオーバーロードするように定義したマクロは,引数の末尾を示す\endinvokeを末尾に付加して呼び出す必要がある.例を示す.

\foo\endinvoke

\foo{bar}{baz}\endinvoke

\foo{bar}\endinvoke

上から順に,引数なし,2引数,および1引数呼び出しに対応する,先に述べたように,TeXのマクロは単純なテキストの置き換えしかできないので,そもそも引数の扱いが普通の言語と異なる.それを回避する方法として,今回は末尾を明記する手法を用いた.

これを実行すると,次の結果を得ることができる.
f:id:hak7a3:20150524201435p:plain
引数の個数に従って,マクロの動作が変化していることがわかる.

overload.styで提供されるマクロ展開部分は完全展開可能にしてあるので,\edefの内部でも利用可能である.実際,overload.styのテストコードでそのような使い方をしている.

制限

overload.styで定義したマクロの呼び出しには,いくつか制限がある.大きなものとしては,

  1. 各引数の先頭に\endinvokeが出現してはいけない
  2. 各引数にバランスの取れていない\fiが存在してはいけない

が挙げられる.これらの問題は引数の末尾か否かの判定処理のためのものである.完全展開可能にするため,どうしてもこのようにするしかなく,現状で解決の糸口はつかめていない.

また,内部でeTeX拡張を使っているので,古いTeX処理系では動作しない.もっとも,現在使用されているほとんどのTeXエンジンがeTeX拡張を認めているため,この制限に引っかかる可能性は低いだろう.

*1:これは上記の記事の回答にも示されている

*2:ようこそ

*3:一応注意しておくと,定義順は自由である