『苦しみのTeX言語プログラミング』をLaTeXで楽しむ方法

今から1年前の[技術書典][techbookfest]（[技術書典16][tcb16]）において[『苦しみのTeX言語プログラミング』][hardtexlang]という本（著者は[やまいも][yamaimo]氏）が出展されました。

https://techbookfest.org/product/8f7TevDUk3TfHMmQPhw61x?productVariantID=qeY5N5fALcsRrm18GD1LZ9

タイトルや表紙絵を見た感じ、トッテモ楽しそう:blush:（苦しそう:worried:）な本ですね。この記事では本書を利用して「**LaTeXで**TeX言語を楽しむ（苦しむ）方法」について解説します。

:::note info
本記事はそもそもTeX言語に関する話であるため、記事中の「LaTeX」は「LaTeXの体系」ではなく「LaTeXフォーマット」を指します。
:::

:::note info
本記事ではTeX言語関連の用語を『苦しみのTeX言語プログラミング』に合わせています。そのため私がいつも使っている用語体系と異なる場合があります。
:::

## 『苦しみ』がスバラシイ話

本書の一番スバラシイ点は、何といっても**​「絶版でないこと」​**でしょう（えっ:astonished:）

TeX言語を学習したことがある人なら知っていると思いますが、TeX言語の参考書の定番として挙げられている本は大概が絶版になっています。今ではAmazonで古本が入手できるため困難さは少しマシになりましたが、それでも定番の本にはプレミア付き価格が付いていたりします。TeX言語の学習が挫折しやすいことを考え合わせると、手を出しにくいのは確かです。

その点、本書は最近発刊された同人書籍であるため、少なくとも電子書籍ならいつでも確実に入手できます。しかも（電子書籍版は[^paper]）700円という低価格です。挫折のリスクを恐れる必要なく気軽にTeX言語の学習を始められます。

[^paper]: 紙書籍と電子書籍のセットは1000円です。

本書の内容上の大きな特徴は「組版の話を扱わず、TeX言語の純粋なプログラミング言語としての側面だけを扱っている」ということです。以下の観点から、これもスバラシイと考えています。

- TeX言語のプログラミングの知識[^tex-typeset]は、LaTeXとも他の多くのプログラミング言語とも“考え方”が大きく異なるため体系的に学習する必要がある。
- 単純にプログラミングの話の方が難しいのでそこで挫折する人が多い。同じ挫折するなら、なるべく早く挫折する方が傷が浅くて済む:upside_down:

[^tex-typeset]: これに対して、TeX言語の組版関連の知識については、LaTeXと“考え方”にそれほど大きな違いがないため、ネット検索等で断片的に知識を入れていく方法でもどうにかなる場合が多くあります。

## 『苦しみ』をLaTeXで楽しむ話

さてそんなスバラシイ『苦しみのTeX言語プログラミング』ですが、注意点もあります。それは本書が**plain TeXを対象としている**ということです。「TeX言語を学習したい」という人の多くが実際に想定しているのは「**LaTeXフォーマット上**でのTeX言語」でしょう。もちろん、plain TeXの実行の方法は本の中で説明されています[^execute]し、また本書の範囲のTeX言語の説明の“ほぼ全て”はLaTeXでも通用する[^core]ため、plain前提であることはそれほど問題にはならないはずです。ただし本書に載っているプログラムをLaTeXで実行する[^latex-cmd]には工夫が必要です。**​「LaTeXでTeX言語したい」​**という人のためにその方法について解説します。

[^execute]: コマンドシェル上の実行を前提としているため単に「`lualatex`の代わりに`luatex`を実行する」というだけの話ですが。
[^core]: 本書の「はじめに」の節の注釈では「plain TeXのコア」と書かれています。恐らく『TeX by Topic』の「‘core’ of plain TeX」と同じ概念を指しているのでしょう。
[^latex-cmd]: つまり`platex`とか`pdflatex`とか`lualatex`とかの、いつも文書を組版するときに使っているコマンドを使うということです。なお、本書は「組版をせずに端末に何かを出力するプログラムを作る」というコンセプトのため、文書作製用の統合環境（LaTeX Workshop）を利用することは難しいと思います。

LaTeXで実行する場合に問題になるのは**​「`\end`が使えない」​**ということです。plainの`\end`は「TeXの処理系を終了させる」ための命令であり、本書においてプログラムの終了のために使われています[^use-end]。

[^use-end]: 実際にはほとんどのコード例に`\end`は書かれていませんが、これがないとTeXが終了しないので、読者が適宜`\end`を補う想定なのでしょう。

```tex:plain TeX
\input{stdio}% 本書の'stdin.tex'
\WriteStdout(Hello!)

% \end で終了する
\end
```

対して、LaTeXでは`\end`は「環境の終了を表す」命令で、例えば`\end{itemize}`のように使われるのでした。つまりLaTeXの`\end`はplainとは別の物であり、`\end`でプログラムを終了できません。

「LaTeXを終了させる方法」といって思いつくのは`\end{document}`です。しかしこれは「文書の**本文**[^document]の終端を示す」ものであるので、これを使うならまず「文書の本文を開始させておく」必要があります。結局、次のように「空の文書を作るコード」を書かないといけないわけです。これはいかにも面倒です。

[^document]: 文書の本文を表すのが「`document`環境」であり、その終了を示すのが`\end{document}`です。

```tex:LaTeX
\input{stdio}
\WriteStdout(Hello!)

% ↓これで終了できる(面倒😟)
\documentclass{article}
\begin{document}
\end{document}
```

幸いなことに、LaTeXにも「途中で**強制終了**させる」ための`\stop`という命令があります。これを実行すると、まだ`\documentclass`が実行される前[^aux-file]であってもLaTeXを終了できます。結局、本書のプログラムをLaTeXで実行させたい場合は`\end`の代わりに **\\stop と書けばいい**ことになります。

[^aux-file]: ちなみに、`\documentclass`の実行前にLaTeXを終了させた場合は補助ファイル（`.aux`）は出力されません。

```tex:LaTeX
\input{stdio}
\WriteStdout(Hello!)

% LaTeXでは \end の代わりに \stop で終了する😃
\stop
```

もし「plainとLaTeXの**両方**で同じプログラムのファイルを実行させたい」という場合は、以下のコード[^def-stop]をどこかに[^write-stop]書きましょう。plainでも`\stop`で終了できるようになります。

[^def-stop]: このコードは「`\stop`が未定義（つまりplain上での実行である）ならば`\end`と同義に定義する」という動作を表します。
[^write-stop]: 本書ではstdio.texをいつも読み込む前提になっているため、このファイルの末尾に追記するといいでしょう。

```tex
\ifx \stop\undefined \let \stop = \end \fi
```

## LaTeXのチョットいい話

これまで「LaTeX上でTeX言語を楽しむ（苦しむ）方法」を説明しました。実は、TeX言語のプログラミングを行うのにLaTeXを使うと、plainを使うときに比べてメリットがあります。それは「**LaTeX独自のプログラミング用の機能が使える**」という点です。

### LaTeXの標準入出力の話

ここではLaTeXの**標準入出力**関連の命令を紹介します。`\ReadStdin`と`\WriteStdout`の代わりにこれらの命令を利用することでstdio.texの読込を省略できます。

* `\typeout{‹出力トークン列›}`： 引数の`‹出力トークン列›`（を展開[^typeout-exp]したもの）を端末に出力する。  
※要するに`WriteStdout(‹出力トークン列›)`と同じ。

* `\typein[\制御トークン]{出力トークン列}`： まず`‹出力トークン列›`を出力して、その後に端末からの入力を待つ。入力を（入力プロセッサで）トークン列に変換した上で、`\制御トークン`を「そのトークン列に展開されるマクロ」として定義する。
※最初に出力があることを除いて`ReadStdin(\制御トークン)`と同じ。

[^typeout-exp]: ここでの展開のルールは`\WriteStdout`と同じ（実は`\edef`と同じ）です。厳密にいうと異なる点がある（`\typeout`の方は“LaTeXレベルの保護”が有効になる）のですが、本書のレベルでは気にしなくていいでしょう。

例えば、本書のリスト1.2（hello.tex）と同等[^typein-out]のプログラムを、LaTeX上ではstdio.texを使わずに次のように書けます。

[^typein-out]: ただし`\typein`は入力の前に何か出力する必要があるため、ここでは`What is your name?`を出力しました。この点だけ元のhello.texと異なります。

```tex:hello.tex（LaTeX版）
% 端末からの入力を \Name に代入
\typein[\Name]{What is your name?}

% 文字列を出力
\typeout{Hello, \Name.}

% LaTeXなので \stop で終了
\stop
```

### ifthenパッケージする話

LaTeX上で**条件分岐**を行うためのパッケージとして[ifthenパッケージ][zr-ifthen]がありますが、このifthenはTeX言語のプログラムを書くときにも利用できます。TeX言語の生の条件分岐やループ構成よりも使いやすいかも知れません。

ただし本書のような「**組版しない**TeX言語のプログラム」を書く時には注意すべき点があります。LaTeX文書の中でパッケージを読むには普通は`\usepackage`命令を使うわけですが、`\documentclass`をまだ実行していない状態でパッケージを読み込みたい場合は`\usepackage`は使えず、代わりに **\\RequirePackage という命令を使う**[^requirepackage]必要があります。

[^requirepackage]: `\RequirePackage`命令の書式は`\usepackage`と全く同じです。なお、そもそも「`\documentclass`より前にパッケージを読む」こと自体がLaTeXではかなり特殊な状況なので、そういう使い方に対応していないパッケージも多いことに注意してください。（ifthenパッケージは対応しています。）

例えば、本書のリスト4.8の中の`\CheckInRange`は`\ifthenelse`を用いて次のように明快に書くことができます。

```tex:LaTeX
% \RequirePackage でパッケージを読み込む
\RequirePackage{ifthen}

\def \CheckInRange(#1<=#2<=#3){
    \ifthenelse {\NOT #2<#1 \AND \NOT #3<#2} {
         \InRangetrue
    }{
         \InRangefalse
    }
}
```

また、リスト5.2の中の`\RepeatImpl`は以下のように`\whiledo`を利用したループで書けます。

```tex:LaTeX
\RequirePackage{ifthen}

\def \RepeatImpl{
    \whiledo {\LoopCount > 0} {
        \LoopBody
        \advance \LoopCount by -1
    }
}
```

## まとめ

冒頭で技術書典の話をしましたが、5月31日から[^offline][「技術書典18」][tcb18]が開催されます。開催期間中であれば『苦しみのTeX言語プログラミング』の**紙書籍**が入手可能です[^booth]。

[^offline]: オフライン（リアル会場）での開催は6月1日(日曜)です。
[^booth]: まあ、[BOOTH][hardtexlang-booth]ではいつでも紙書籍が入手できるようですが。

またTeX言語に関していうと、技術書典18では新刊の[『作ってわかるTeX言語』][impltexlang]という本（著者は[だめぽラボ][damepolab]）も出展されます。

https://techbookfest.org/product/5DXS1MRCfPrVvKaYxWdGPW

「TeX言語に少し関心があるけど、参考書が入手困難だから手が出しづらかった…」という人には今は絶好のタイミングといえます。技術書典18を契機にして、素敵:scream:なTeX言語の世界に足を踏み入れてみましょう！:information_desk_person:

[damepolab]: https://lab.miz-ar.info/
[hardtexlang-booth]: https://booth.pm/ja/items/5799095
[hardtexlang-tcb]: https://techbookfest.org/product/8f7TevDUk3TfHMmQPhw61x?productVariantID=qeY5N5fALcsRrm18GD1LZ9
[hardtexlang]: https://www.yamaimo.dev/entry/HardTexLang
[impltexlang]: https://lab.miz-ar.info/implementing-tex-lang/
[impltexlang-tcb]: https://techbookfest.org/product/5DXS1MRCfPrVvKaYxWdGPW
[tcb16]: https://techbookfest.org/event/tbf16
[tcb18]: https://techbookfest.org/event/tbf18
[techbookfest]: https://techbookfest.org/
[yamaimo]: https://www.yamaimo.dev/
[zr-ifthen]: https://qiita.com/zr_tex8r/items/71ae46c9c4e8cb575073