今から1年前の技術書典(技術書典16)において『苦しみのTeX言語プログラミング』という本(著者はやまいも氏)が出展されました。
タイトルや表紙絵を見た感じ、トッテモ楽しそう(苦しそう)な本ですね。この記事では本書を利用して「LaTeXでTeX言語を楽しむ(苦しむ)方法」について解説します。
この記事ではTeX言語関連の用語を『苦しみのTeX言語プログラミング』に合わせています。そのため私がいつも使っている用語体系と異なる場合があります。
『苦しみ』がスバラシイ話
本書の一番スバラシイ点は、何といっても「絶版でないこと」でしょう(えっ)
TeX言語を学習しようと考えた人なら知っていると思いますが、TeX言語の参考書の定番として挙げられている本は大概が絶版になっています。今ではAmazonで古本が入手できるため困難さは少しマシになりましたが、それでも定番の本にはプレミア付き価格が付いていたりします。TeX言語の学習が挫折しやすいことを考え合わせると、手を出しにくいのは確かです。
その点、本書は最近発刊された同人書籍であるため、少なくとも電子書籍ならいつでも確実に入手できます。しかも(電子書籍版は)700円という低価格です。挫折のリスクを恐れる必要なく気軽にTeX言語の学習を始められます。
『苦しみ』をLaTeXで楽しむ話
さてそんなスバラシイ『苦しみのTeX言語プログラミング』ですが、注意点もあります。それは本書がplain TeXを対象としているということです。「TeX言語を学習したい」という人の多くが実際に想定しているのは「LaTeXフォーマット上でのTeX言語」でしょう。もちろん、plain TeXの実行の方法は本の中で説明されています1し、また本書の範囲のTeX言語の説明の“ほぼ全て”はLaTeXでも通用する2ため、plain前提であることはそれほど問題にはならないはずです。ただし本書に載っているプログラムをLaTeXで実行する3には工夫が必要です。「LaTeXでTeX言語したい」という人のためにその方法について解説します。
LaTeXで実行する場合に問題になるのは「\end
が使えない」ということです。plainの\end
は「TeXの処理系を終了させる」ための命令であり、本書においてプログラムの終了のために使われています4。
\input{stdio}% 本書の'stdin.tex'
\WriteStdout(Hello!)
% \end で終了する
\end
対して、LaTeXでは\end
は「環境の終了を表す」命令で、例えば\end{itemize}
のように使われるのでした。つまりLaTeXの\end
はplainとは別の物であり、\end
でプログラムを終了できません。
「LaTeXを終了させる方法」といって思いつくのは\end{document}
です。しかしこれは「文書の本文5の終端を示す」ものであるので、これを使うならまず「文書の本文を開始させておく」必要があります。結局、次のように「空の文書を作るコード」を書かないといけないわけです。これはいかにも面倒です。
\input{stdio}
\WriteStdout(Hello!)
% ↓これで終了できる(面倒😟)
\documentclass{article}
\begin{document}
\end{document}
幸いなことに、LaTeXにも「途中で強制終了させる」ための\stop
という命令があります。これを実行すると、まだ\documentclass
が実行される前6であってもLaTeXを終了できます。結局、本書のプログラムをLaTeXで実行させたい場合は\end
の代わりに \stop と書けばいいことになります。
\input{stdio}
\WriteStdout(Hello!)
% LaTeXでは \end の代わりに \stop で終了する😃
\stop
もし「plainとLaTeXの両方で同じプログラムのファイルを実行させたい」という場合は、以下のコードをどこかに書く(例えばstdio.texの末尾に追記する)といいでしょう。
\ifx \stop\undefined \let \stop = \end \fi
このコード7を実行すると、plainでもLaTeXでも\stop
で終了できるようになります。
LaTeXのチョットいい話
これまで「LaTeX上でTeX言語を楽しむ(苦しむ)方法」を説明しました。実は、TeX言語のプログラミングを行うのにLaTeXを使うと、plainを使うときに比べてメリットがあります。それは「LaTeX独自のプログラミング用の機能が使える」という点です。
LaTeXの標準入出力の話
ここではLaTeXの標準入出力関連の命令を紹介します。\ReadStdin
と\WriteStdout
の代わりにこれらの命令を利用することでstdio.texの読込を省略できます。
-
\typeout{‹出力トークン列›}
: 引数の‹出力トークン列›
(を展開8したもの)を端末に出力する。
※要するにWriteStdout(‹出力トークン列›)
と同じ。 -
\typein[\制御トークン]{出力トークン列}
: まず‹出力トークン列›
を出力して、その後に端末からの入力を待つ。入力を(入力プロセッサで)トークン列に変換した上で、\制御トークン
を「そのトークン列に展開されるマクロ」として定義する。
※最初に出力があることを除いてReadStdin(\制御トークン)
と同じ。
例えば、本書のリスト1.2(hello.tex)と同等9のプログラムを、LaTeX上ではstdio.texを使わずに次のように書けます。
% 端末からの入力を \Name に代入
\typein[\Name]{What is your name?}
% 文字列を出力
\typeout{Hello, \Name.}
% LaTeXなので \stop で終了
\stop
ifthenパッケージする話
LaTeX上で条件分岐を行うためのパッケージとしてifthenパッケージがありますが、このifthenはTeX言語のプログラムを書くときにも利用できます。TeX言語の生の条件分岐やループ構成よりも使いやすいかも知れません。
ただし本書のような「組版しないTeX言語のプログラム」を書く時には注意すべき点があります。LaTeX文書の中でパッケージを読むには普通は\usepackage
命令を使うわけですが、\documentclass
をまだ実行していない状態でパッケージを読み込みたい場合は\usepackage
は使えず、代わりに \RequirePackage という命令を使う10必要があります。
例えば、本書のリスト4.8の中の\CheckInRange
は\ifthenelse
を用いて次のように明快に書くことができます。
% \RequirePackage でパッケージを読み込む
\RequirePackage{ifthen}
\def \CheckInRange(#1<=#2<=#3){
\ifthenelse {\NOT #2<#1 \AND \NOT #3<#2} {
\InRangetrue
}{
\InRangefalse
}
}
また、リスト5.2の中の\RepeatImpl
は以下のように\whiledo
を利用したループで書けます。
\RequirePackage{ifthen}
\def \RepeatImpl{
\whiledo {\LoopCount > 0} {
\LoopBody
\advance \LoopCount by -1
}
}
まとめ
冒頭で技術書典の話をしましたが、5月31日から11「技術書典18」が開催されます。開催期間中であれば『苦しみのTeX言語プログラミング』の紙書籍が入手可能です12。
またTeX言語に関していうと、技術書典18では新刊の『作ってわかるTeX言語』という本(著者はだめぽラボ)も出展されます。
「TeX言語に少し関心があるけど、参考書が入手困難だから手が出しづらかった…」という人には今は絶好のタイミングといえます。技術書典18を契機にして、素敵なTeX言語の世界に足を踏み入れてみましょう!
-
コマンドシェル上の実行を前提としているため単に「
lualatex
の代わりにluatex
を実行する」というだけの話ですが。 ↩ -
本書の「はじめに」の節の注釈では「plain TeXのコア」と書かれています。恐らく『TeX by Topic』の「‘core’ of plain TeX」と同じ概念を指しているのでしょう。 ↩
-
つまり
platex
とかpdflatex
とかlualatex
とかの、いつも文書を組版するときに使っているコマンドを使うということです。なお、本書は「組版をせずに端末に何かを出力するプログラムを作る」というコンセプトのため、文書作製用の統合環境(LaTeX Workshop)を利用することは難しいと思います。 ↩ -
実際にはほとんどのコード例に
\end
は書かれていませんが、これがないとTeXが終了しないので、読者が適宜\end
を補う想定なのでしょう。 ↩ -
文書の本文を表すのが「
document
環境」であり、その終了を示すのが\end{document}
です。 ↩ -
ちなみに、
\documentclass
の実行前にLaTeXを終了させた場合は補助ファイル(.aux
)は出力されません。 ↩ -
このコードは「
\stop
が未定義(つまりplain上での実行である)ならば\end
と同義に定義する」という動作を表します。 ↩ -
ここでの展開のルールは
\WriteStdout
と同じ(実は\edef
と同じ)です。厳密にいうと異なる点がある(\typeout
の方は“LaTeXレベルの保護”が有効になる)のですが、本書のレベルでは気にしなくていいでしょう。 ↩ -
ただし
\typein
は入力の前に何か出力する必要があるため、ここではWhat is your name?
を出力しました。この点だけ元のhello.texと異なります。 ↩ -
\RequirePackage
命令の書式は\usepackage
と全く同じです。なお、そもそも「\documentclass
より前にパッケージを読む」こと自体がLaTeXではかなり特殊な状況なので、そういう使い方に対応していないパッケージもあることに注意してください。(ifthenパッケージは対応しています。) ↩ -
オフライン(リアル会場)での開催は6月1日(日曜)です。 ↩