とあるプログラミング言語1が超絶アレなためムシャクシャしたので、チョットTeX芸してみた。
ループや再帰なしで100万回Hello, World!するには? #ゆっくり解説 ショート始めました。https://t.co/2tUpBoErLh pic.twitter.com/UFXdu7QyME
— えびま (@evima0) 2024年2月22日
想定はCみたいだけれど、関数型※(TeX言語🤮)ならこう書けるよ🤯
— 某ZR(ざんねん🙃) (@zr_tex8r) 2024年2月23日
(1ページ53行(最終ページだけ49行)で18868ページ)
※諸説あります#TeX #TeX言語 #TeX芸人 pic.twitter.com/QV9T9Gqwmd
※上記のプログラムはplain TeX用のものである。tex
コマンドでコンパイルするとDVIファイル、pdftex
でコンパイルするとPDFファイルが得られる。以下、この記事で扱うコードはplain TeXを前提とする。
とりあえず
なるべくTeX言語特有の変態な方法を使う
という方向性にこだわってみた。
参考:フツー(?)の方法
なお、元ネタで使っている方針はもちろんTeX言語でも使える。TeX言語チョットデキル人であれば思いつくであろう2。
\let\z.\def~{\z}\def\y{\edef~{~~~~~~~~~~}}\y\y\y\y\y\y \def\z{Hello world!\par}~\bye
※TeXを対話モードで使っていて「反復処理を書きたい」という場合に、このパターンを実際に使うことがたまにある。(TeXでループを書くのは面倒なので。)
変態な方法
{\catcode`\m=\active\gdefm{\hbox{Hello world!}$\par$}} \mathcode`m="8000$\romannumeral1000000000\relax$\bye
ポイントは\romannumeral1000000000
である。ローマ数字で“10億”を出力しようとしているが、(TeXの)ローマ数字で最大の数字は“m=1000”なので、結果的にTeXはこのコードをm
を100万個並べた文字列に展開する。これでループ的な実行制御なしで“同じトークン100万個”を得ることに成功した🙃
ただしこのm
のカテゴリコードは123なので、このままでは“m”以外のテキストを出力するのには使えない。カテゴリコードが12の文字トークン4でマクロを実行させたい……となると、math-acriveを使うことが考えられる。
文字のmath codeを"8000
に設定することを“math-active”という5。文字をmath-activeにすると、数式モード中で当該の文字の(カテゴリコードが11または12の)文字トークンが実行されたときに「代わりにその文字のアクティブ(カテゴリコード13)な文字トークンが実行される」という動作になる。標準のplain TeX(やLaTeX)では数式モード中での'
の入力でプライム記号(\prime
)が上添字として出力されるが、この挙動は'
をmath-activeにすることで実現している。
今の場合はm
の入力で“Hello world!”を出力させたいので、アクティブなm
にマクロを定義した上で\mathcode`\m="8000
を設定する。その上で、数式モードに入って\romannumeral1000000000
を実行すればよいことになる。ただし数式モードに入るのは飽くまでmath-activeのためで文字列自体は非数式で出力したいなので\hbox
を使う。さらに「数式モード中では改段落ができない」のを回避するために「一旦数式モードを終結してから改段落してまた数式モードに入る」という対策をとった。
まとめ
新しいテフライブが無事にリリースできるといいですね😊(まとめろ)