2016/02/09

LaTeXで連番リストに丸数字(\ajMaru)を使えたはずだけどhyperrefで困る話

LaTeXで丸数字の連番リスト環境の基本

そもそもLaTeXで丸数字を使いたいときは、otfパッケージajmacros.styの機能を使うのが一番お手軽です。 このスタイルでは、数値を指定してさまざまな囲み数字のグリフ(あれば)を呼び出すという便利な機能が提供されています。 たとえば、ふつうの丸数字であれば、\ajMaru{数値}として出力できます。

\ajMaru{1}、\ajMaru{100}、\ajMaru{101}

一方、enumerate環境でラベルのスタイルを変えたいときは、\theenumiとか\theenumiiといったコマンドを再定義します。 \theenumi\theenumiiは、それぞれ「enumi」や「enumii」という名前のカウンタに対応した「アラビア数字」に展開されるコマンドです。 その結果がenumerate環境でラベルを表示するのに使われているので、これらのコマンドの挙動を変えることで別の種類の数字を出力できるというわけです。 たとえばこんなふうにすれば、ラベルが大文字のローマ数字であるような連番環境が作れます。

\renewcommand{\theenumi}{\Roman{enumi}}
\begin{enumerate}
  \item 最初\label{A}
  \item\label{B}
\end{enumerate}
最初は\ref{A}、次は\ref{B}。

以上の知見を組み合わせれば、こんなふうにして丸数字の連番環境が作れそうです。

\renewcommand{\theenumi}{\ajMaru{enumi}}

しかしこれはうまくいきません。\ajMaruの引数は数値でなければならず、enumiはあくまでもカウンタの名前だからです。

ではどうすればいいかというと、ajmacros.styに用意されている\ajLabelというコマンドを使います。 このコマンドは、後続の\ajMaru{enumi}の中身を実際のカウンタ値として取り出してくれるように定義されています。

\renewcommand{\theenumi}{\ajLabel\ajMaru{enumi}}
\begin{enumerate}
  \item 最初\label{A}
  \item\label{B}
\end{enumerate}
最初は\ref{A}、次は\ref{B}。

hyperrefと一緒に使えなくなっているっぽい(2016年2月現在)

本当ならこれで話は終わりのはずなんですが、相互参照をクリッカブルにしてくれるhyperrefパッケージを同時に使うと話がややこしくなります。 hyperrefは、相互参照をクリッカブルにするためにカウンタ関連の機能をいろいろ勝手にオーバーライドするという鬼仕様なのですが、 ajmacros.styではそれに振り回されないように、 hyperrefを読み込んだ場合には\begin{document}の時点で\ajLabelなどをhyperref用にカスタマイズし直してくれます。

しかし、さらに厄介なことに、hyperrefはときどき内部の振る舞いをドラスティックに変更します。 そのため、せっかく再定義されている\ajLabelがまた使えなくなるという事態が2016年2月現在では発生しているようです。 具体的には、以下のような例で、上記のような事情を理解していないとちょっと追跡しにくいエラーが起きます。

\documentclass[dvipdfmx]{jsarticle}
\usepackage{otf}
\renewcommand{\theenumi}{\ajLabel\ajMaru{enumi}}
\usepackage{hyperref} % hyperrefを使う
\begin{document}
\begin{enumerate}
  \item 最初\label{A}
  \item\label{B}
\end{enumerate}
最初は\ref{A}、次は\ref{B}。
\end{document}

実行例

...
! Undefined control sequence.
\ajLabel ...abel \@arabic \else \Hy@ReturnAfterFi
                                                  \hyperref@ajLabel #1\fi {
l.17  \item 最
              初\label{A}
?

エラーが起きている\Hy@ReturnAfterFiは、かつてはhyperref.sty内で定義されて使われていたようですが、現在のhyperrefでは使われていないため、このような事態になってしまうようです。hyperrefパッケージのSVNのログを見ると、どうやら2011年4月に消えたようですね。

[hyperref-svn] oberdiek: r1291 - trunk
http://mail.gnu.org.ua/mailman/listarchive/hyperref-svn/2011-04/msg00002.html

上記のログを見る限り、oberdiekバンドルのltxcmdsパッケージで定義されている\ltx@ReturnAfterFiを使うようにしたので、\Hy@ReturnAfterFiをディスコンにしたようです。 \ajLabelの再定義では、この\Hy@ReturnAfterFiを利用しているので、上記の例がうまく処理できない結果になっているようです。

そこで、\Hy@ReturnAfterFi\ltx@ReturnAfterFiに変更するだけの以下のパッチをajmacros.sty(1.7b6)に当てて試したところ、意図した挙動に戻りました。 (\Hy@ReturnAfterFi\ltx@ReturnAfterFiの定義は同一なので当然といえば当然なのですが。。)

--- ajmacros.sty.org    2016-02-09 16:16:17.700785982 +0900
+++ ajmacros.sty        2016-02-09 16:15:57.548561902 +0900

@@ -685,7 +685,7 @@
 %      \def\check@UTF##1##2##3{\ifx\UTF##1\0x##2\else##3\fi}}{}}
 \gdef\ajRedefine@ajCommands{\@ifpackageloaded{hyperref}{%
        \let\hyperref@ajLabel\ajLabel
-       \def\ajLabel##1##{\ifHy@pdfstring\Hy@ReturnAfterElseFi\hyperref@ajLabel\@arabic\else\Hy@ReturnAfterFi\hyperref@ajLabel##1\fi}%
+       \def\ajLabel##1##{\ifHy@pdfstring\Hy@ReturnAfterElseFi\hyperref@ajLabel\@arabic\else\ltx@ReturnAfterFi\hyperref@ajLabel##1\fi}%
        \ajRedefine@ajCommand\"${Lig"$}\"&{Lig"&}\!*{Lig>.}\ajLig{Lig}\ajPICT{PICT}\"({PICT}\ajVar{Var}\@nil\@nil
        \aj@Redefine@ajCommand!{{Maru}!|{KuroMaru}""{Kaku}"#{KuroKaku}!~{MaruKaku}"!{KuroMaruKaku}\@nil\@nil
        \def\!J##1!K{\ifHy@pdfstring(##1)\else\expandafter\ifx\csname ajLig(##1)\endcsname\relax\@ajnumber{##1}{Kakko}%

hyperrefは、電子書籍をLaTeXで制作するうえでは唯一無二のパッケージなのですが、ときどきこういう面倒が起きるのがつらい。。

まとめ

またhyperrefか。

2016/01/27

技術書編集者として「これはやられた!」2015年の本

技術書の年間ランキング的なものについて、編集者たちに「これはやられた!」と思う他社の本を候補として出させたら面白いのでは、という会話を小耳にはさみました。これはまたとないアマゾンアソシエイトの機会!ということで、勝手に自分の候補を上げてみます。

と思ったものの、新刊の技術書をそんなにたくさん読んでいないうえに、去年「これはやられた!」と思った本はいずれも技術書ではなく、どちらかというと数学書っぽい本ばかりでした。それでも、ジュンク堂池袋本店の「新春座談会 このコンピュータ書がすごい! 2015年版」で取り上げられた本ばかりだし、たぶん技術者が読む(べき)本としても妥当なはずです。

コンピュータは数学者になれるのか? -数学基礎論から証明とプログラムの理論へ-

いま自分の本棚を見返したら、この本の隣にたまたま『日本の著作権はなぜこんなに厳しいのか』が並んでいて、一瞬だけ姉妹書に見えました。疑問形タイトル、文芸系とかビジネス系の出版社だと割と普通に見かけるけど、自分で本を企画するときには扱い方がわからず避けてしまうので、そういう書名を使いこなせる編集者になりたいです。というか、たぶん疑問形タイトルって、「これは既成の考え方をなぞった本ではなく、なおかつ人類は読むべきである」ことについて相当な自信がないと付けられない書名な気がします。

この本の場合、コンピュータと数学者のことを「算術計算に秀でたモノ」と考えている人にとっては、確かに「既成の考え方をなぞった本」ではないのでしょう。しかし、コンピュータとは自分が考えたプログラムが本当に動くことを確かめるためのものであるという人や、数学者はコーヒーから証明を生成する仕事であると気づいている人にとっては、どこかで見聞きして知っていたり知らなかったりする話にぐさっと明快な筋道を通してくれる本でした。一般向けの数学の読み物で見かける話も含まれてますが、call/ccは背理法ありの古典論理で純粋関数型言語は直感主義論理に対応しているんだという第5章のクライマックスに至る話を素で楽しめるのは、実際にプログラムを書いている技術者の特権だろうと思います。

出版社は青土社です。選択公理の読み物として一部で有名な‟The Pea and the Sun: A Mathematical Paradox”(Leonard M. Wapner)の翻訳である『バナッハ=タルスキの逆説 豆と太陽は同じ大きさ?』をはじめ(原書しか読んでないので翻訳の出来は知らない)、意外に「え?」っていう理学系の本も出してくるし、割と好きです。「現代思想」とか「ユリイカ」でも思想的な文脈で現代数学の記事をたまに掲載しているし、そのうち計算機科学や機械学習の特集もあるに違ない。

圏論の歩き方

Haskellを使うのに圏論はいらないって言うけど、みんな圏論圏論って言ってるので、どうしたって圏論が気になりますよね。そんな人間を狙いうちする本が日本評論社から発売されました。タイトルどおり、圏論の名所をめぐるツアーガイドのような本です。いつか自分の足で行ってみたいけど余裕がなくて行けない場所へ行った気になれる本です。去年の夏に読んで、いまこうやって記事を書くつもりで内容を要約しようとしても、さっぱり具体的な言葉にできないんですが、そのへんもツアーガイドに似ています(実際、「地球の歩き方」なんかにしても、行く場所を決めるときに読んだ内容をあらためて説明しろと言われても言葉に詰まりそう)。

正直、この本のうち計算機に関する部分については、まさに自分でこんな本を作りたかったという気にさせてくれる本でした。この本が企画として面白いと思うのは、コンピュータ書でいえばフレームワークに対する「クックブック」のような本を、数学の一分野で形にしてしまった点です。数学書、コンピュータ書でいえば「コードの動作について説明しただけ」だったり「コード読めばわかるよね」だったり、そんな立ち位置の教科書が少なくない気がします。コンピュータ書の場合には、実行例を見せることで「どんな場面でどんなコードが必要なのか」を説明できたりしますが、それを数学書でやったのがこの本なのかなあと思いました。いわば「圏論の実行例」。あるいは「圏論のクックブック」。もし何らかの事情で圏論について本当に「わかる」必要があるなら、体系的に書かれた教科書を読みながら紙と鉛筆で勉強するのが近道なんですが、そうやって教科書の証明を読み進めるときの「実行例」だけが本として、しかも圏論みたいな分野で出たということで、自分のなかでは「これはやられた!」一冊でした。

あなたの知らない超絶技巧プログラミングの世界

自分が過去に企画にできなかった本が企画化され、しかも想像以上に出来がいいのだから、「これはやられた!」一冊として選ばざるをえない。発売当時、くやしさをばねに紹介記事を書いたので、そちらを読んでください。

2016/01/08

英数字文字列を任意位置で改行するTeXパッケージを使う話

技術系のドキュメントでは、長い連続した英数字からなる文字列を等幅フォントで組む必要に迫られることが多々あります。 本文中にそんな文字列が連続して出現する原稿を、字間が異常に空いたり版面をはみ出したりすることなく組版するためのベストプラクティスは、有識者の間でも意見が分かれるようです。 うまく自然な改行位置に収まるように原稿のほうに手をいれられればベストですが、政治的経済的な理由で困難だったり、そもそも解説内容からして無理筋という場合もあります(Javaの変数名とかJavaの変数名とか)。

よくあるのは、空白やハイフンや記号文字の直後に恣意的な改行位置を指定する、という方法でしょう。 変数名を英単語の組み合わせだとみなすなら、この方法が自然に思えます。 キャメルケースの大文字の手前を恣意的な改行位置にすることもありうるでしょう。

しかし、「英単語として有意味な改行位置」は、このような文字列にとって必ずしも適切な改行位置ではないはずです。 たとえば、空白とかハイフンで区切ってしまうと、文字列のその部分に文字通り空白やハイフンがあるのか、たまたま改行があって空白やハイフネーション記号が挿入されているのか、区別しにくくなります。 キャメルケースの大文字の手前で改行されていると、その位置に文字通りの空白が入る可能性が気になって仕事になりません。 もちろん読者として読むなら意味を考えて区別できるんですが、作り手側にいると「勘違いして読まれたらまずいのでは」という不安をぬぐえないということです。

で、最近は、任意の文字間で改行するという思い切ったルールにするほうが理に適っているのではないかと考えるようになりました。 つまり、英数字の文字列ではあるけど、日本語や中国語のように組むわけです。 任意の音節区切りで改行くらいのほうが穏当な気もしますが、Webページだとword-wrap: break-word;が指定されている例も見かけるし、これをTeXでやってみようというのが本題です。

結論から言うと、seqsplitというパッケージがあります。もともとはDNAなんかの塩基配列を組むためのパッケージで、TeX Liveにも入ってます。 つまり、acgtの4文字からなる長大な文字列をページに組むことを目的にしています。 これを以下のような感じに使うことで、任意の位置で改行可能なバージョンの\textttが実現できます(実行例

\usepackage{seqsplit}
\usepackage{fancyvrb}
\VerbatimFootnotes

\makeatletter
% \def\seqinsert{\ifmmode\allowbreak\else\hspace{0pt plus 0.02em}\fi
\def\wordwraptt{\begingroup\obeyspaces\do@codeline}
\def\do@codeline#1{\texttt{\seqsplit{#1\relax}\endgroup}}
\makeatother

\begin{document}

Wikipediaによると、Brain*uckでは
\wordwraptt{%
++++++++[>++++[>++>+++>+++>+<<<<-]%
>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>%
.<-.<.+++.------.--------.>>+.>++.%
}というHello World!プログラムが書けます。

\end{document}

fancyvrbパッケージを読み込んでいるのは、\VerbatimFootnotesを使うためです。 このコマンドが提供するような仕組みがないと、\wordwrapttを脚注に配したときにスペースがなくなってしまいます。

改良したい点として、事前に中身の文字列を数えてあまり短いものは改行しないようにするといった処理もしたほうがよさそう。 (\penaltyによる調整は試してみたけれどあまりうまくいかなかった。)

なお、上記のような異常ケースでない場合は、Listingsというパッケージを使って\lstset{breaklines=true, breakatwhitespace=true}という設定をしてあげることで、そこそこ妥当な結果になるかもしれません。

(追記)さっそく改良案をいただきました。

あながちネタでもないと思っていて、似たようなことは考えていました(さすがに雪だるまをつかう発想はなかったけれど)。 上の例のコードブロックではコメントアウトしてある\seqinsertの再定義部分を書き換えると、このようなことが可能になります。


宣伝

TechBoosterがC89で頒布した6点のラインナップでは、上記のような仕組みを使うことで、Re:VIEWからでは制御困難な長い変数名の折り返し調整をなんとかしてみました。 が、コマンド中のスペースの存在を根本的に見逃すという大変残念かつ申し訳ない失敗をしています。本当にすみません。 電子版はなおっているはずなので、本誌に挿入されているQRコードでぜひ電子版も入手してください><

TechBooster in C89 特設ページ

というわけで、いろいろ微妙なTeXマクロだけど(LaTeXのことは知らない)、冒頭のツイートで思い出したのでネタとして。

2015/12/29

2016年賀状

年賀状書いた。
%!PS
(ps3d.inc) run
<< /PageSize [285 420] >> setpagedevice

-70 0 100 translate3d
[0 0 690 2] set-eye
[2 1 0.5] -45 rotate3d

/setrandcolor { % def
    /r1 {rand 5 mod 3 div} def
    /r2 {rand 4 mod 4 div} def
    /r3 {rand 3 mod 4 div} def
    r1 r2 r3 setrgbcolor
} def

/DS-Chocolade findfont [140 0 0 400 0 0] makefont setfont

1 1 20 { % for
  newpath
  0 1 20 { % for
    /y exch def
    0 y 320 mul moveto
    (2016) true charpath
  } for
  2d-path-convert
  clip
  gsave

  newpath
  0 20 300 { % for
    /x exch def
    /w 20 def
    gsave
      x 0 0 moveto3d
      x w add 0 0 lineto3d
      x w add 6000 0 lineto3d
      x 6000 0 lineto3d
      x 0 0 lineto3d
      closepath
      setrandcolor
      fill
      grestore
  } for

  grestore
  0.7 0 0.1 setrgbcolor
  stroke
  showpage
} for

2016.pdf by Keiichiro Shikano

今年はBill CasselmanさんのPostScript用3Dライブラリ ps3d.inc を利用しました(参照)。 使っているフォントは DS Chocolade。 スターウォーズは関係ないんだからね。

ps3d.inc はとても読みやすいソースで、しかも開発者のBillさん自身が Mathematical Illustration という本でわりと丁寧にマニュアルっぽいものを書いてくれているので、PostScriptで3Dを描いてみたい人にはお勧めです。 この本自体も、PostScriptを書きながら初等幾何も学べるという、実に面白い内容です(年に一回しか開かないけど)。 ただ、概説より先の解説はちょっと端折り気味なので、結局はこのライブラリの技術的根拠になっている Jim Bulin's Corners 1 も参照するはめになったけどな! ちなみに、Jim Bulin's Corners の vol.1 は元同僚が翻訳書(アフィリエイト)を出したので日本語で読めるんです。すごい。

過去のやつ。

2015/12/24

Re:VIEWな原稿のためのTeXフォーマットを作ってみたよ

tl:dr
  • これはTeX & LaTeX Advent Calendar 2015の24日目の記事である
  • Re:VEIW、LaTeXでPDFを作るんなら、そもそもRubyもRe:VIEWそのものも不要じゃない?
  • そこでRe:VIEW記法を直でコンパイルするTeXを作ってみた

(ここから本編)

今年の自分の仕事を軽く振り返ってみたところ、前職での最後の出版物となった『エクストリームプログラミング』をRe:VIEWを使って制作したり、無職になってから声を書けていただいた同人サークルTechBoosterの書籍制作でRe:VIEWが圧倒的に利用されていたり(年末のコミケで新刊解説書も売ってるよ!)、これまでになくRe:VIEWとの因縁めいた縁を感じる一年だった気がします。そこで、なにかRe:VIEWに関連したネタで記事が書けたらいいなあと思いました。

というわけで、TeX & LaTeX Advent Calendar 2015のためのネタとして、Re:VIEWとTeXがもっと仲良くなれるかもしれない方法を考えてみました。TeX & LaTeX Advent Calendar 2015の昨日12月23日の担当はdoraTeXさん、明日最終日の担当はzr_tex8rさんです。

さて、Re:VIEWの話を書くと決めたはいいものの、今年のTeX & LaTeX Advent Calendarには「今さら人に聞けない、TeXのキホン」という重点テーマが設定されています。Re:VIEWがTeXのキホンとは思えない。そこで、とりあえず形だけでも重点テーマを消化すべく、まずはTeXのキホンのひとつといえるアクティブ文字について説明することにします。TeXのキホンに興味がない人は「2. Re:VIEW風のシンタックスで書けるTeXを作ってみた」まで読み飛ばしてかまいません。

アクティブ文字とは

TeXとかLaTeXには、俗にいうマクロとかコマンドと呼ばれるものがあるのはご存じですよね。 バックスラッシュとか円記号の後ろに英文字が並んでるやつです。 このマクロとかコマンドを使って、ページに出力する要素の構造を指定したり、繰り返し入力する手間を省いたり、特殊な記号を入力したり、装飾を施したり、絵を描いたりできるのでした。

このマクロやコマンド、ほとんどの場合は「\から始まる文字列」(専門用語ではコントロールシーケンス)という形式の名前で定義するんですが、実はもう一つ方法があって、それが本節のテーマであるアクティブ文字です。 ようするに、単なる文字がまるでマクロやコマンドのように定義済みの内容に展開される機能がTeXにはあって、それをアクティブ文字と呼んでいます。

アクティブ文字「~」(チルダ)

アクティブ文字の代表例は「~」(チルダ)です。 ふつうのTeX環境における「~」には、HTMLにおける&nbsp;と同じく、ノーブレークスペースという機能が割り当てられています。 つまり、改行されるのは嫌だけどアキが欲しいような場所に「~」を挿入することで、TeXの組版処理を制御できます。

See Figure 1.1.  % 「Figure」と「1」の間で改行される可能性がある

See Figure1.1.   % 「Figure」と「1」の間で改行されないが、アキもない

See Figure~1.1.  % 「Figure」と「1」の間で改行されず、アキも入る

この挙動が、実はTeXの実装でハードコードされている機能ではなく、次のような感じでアクティブ文字「~」として「定義」されているというわけです。

\catcode`\~=13
\def~{\leavevmode\nobreak\ }

\catcodeというのが文字の種類(カテゴリコードと呼ばれています)を変更するためのTeXプリミティブで、「13」がアクティブ文字のカテゴリコードです。\catcodeで文字のカテゴリコードを13に変更すると、通常のコントロールシーケンス(バックスラッシュで始まる文字列で作れるやつ)とまったく同じ要領で、\defを使って動作を定義できます。

好きな文字をアクティブ文字に変更してみよう

もちろん、自分で好きな文字をアクティブ文字に変更して、その動作を好きなように定義することも可能です。 たとえば、「*」という文字を「\item 」に展開できると楽ができそうですよね。

\begingroup
\catcode`\*=13
\def*{\item }

\begin{itemize}
* 箇条書きが、
* こんなに、
* 書きやすく!
\end{itemize}
\endgroup
あるいは、文中の「8」という文字をすべて雪だるまにすると楽しそうですね(scsnowmanパッケージマジ便利)。
She's the last of the V8s!

\begingroup
\catcode`\8=13
\def8{\scsnowman[hat=true,muffler=red,arms=true]}

V8! V8!

\endgroup

問題は、こんなふうに気軽に「*」や「8」の意味を変えてしまうと、「*」や「8」という文字を本来の意味で使えなくなってしまうことです。とくに「*」は、文章中で使えないだけならまだしも(それだけでも困る場面はあるでしょうが)、\section*{連番なしの節タイトル}のような一般的なコマンドで使えなくなってしまうのは困ります。 実際、上記の2例では、\begingroup\endgroupを使うことで、これらがアクティブ文字として有効になるスコープを制限しています。

そんなわけで、こんなに便利で楽しいアクティブ文字ですが、ふつうにTeXやLaTeXで文章を書くときに利用できるものは最初に紹介した「~」のみです。残念ですね。 (改行文字を段落の終わりとして再定義して特定の環境内で暗黙に利用しているようなケースはあります。)

Re:VIEW風のシンタックスで書けるTeXを作ってみた

アクティブ文字で、なにかもっと面白いことはできないでしょうか。

前の節では、「*」という文字を再定義して\itemのように使う方法を紹介しました。 よく考えるとこれは、Re:VIEW記法における箇条書きのシンタックスそのものです。 ひょっとしたら、アクティブ文字をさらに駆使することで、バックスラッシュと波カッコというTeXやLaTeXの記法(悪名高い)に縛られずに原稿を執筆できるところまで持っていけるのではないでしょうか。いや持っていけるに違いない。

シンプルな箇条書きの記法

長い前置きはこれくらいにして、ここからはさまざまなRe:VIEW記法をTeXで実装していくことにしましょう。 まずはRe:VIEWの箇条書き記法をTeX上で再現してみます。

新しい段落が「*」で始まったらitemize環境に入り、新しい段落が出てきたら抜けて、その間に出てくる「*」は問答無用で\itemにするが、それ以外の「*」はそのまま印字する、という動作なら、*をアクティブ文字にしてこんな感じに書けそうです。

\newif\if@itemize
\chardef\active=13
\begingroup
\catcode`\*=\active
\gdef*{%
  \ifvmode\@itemizetrue\begin{itemize}
    \everypar={\end{itemize}\@itemizefalse}
  \fi
  \itemize@to@eol}%
\endgroup

\def\itemize@to@eol{\begingroup\catcode`\^^M=12 \@@itemize@to@eol}
{\catcode`\^^M=12 \catcode`\^^I=5 %
 \gdef\@@itemize@to@eol#1^^M{\review@itemize@head#1 \endgroup}}
\def\review@itemize@head{\if@itemize\item \else*\fi}

TeXやLaTeXのシンタックスは捨てることにしたので、ほかのコマンドに「*」が出てくる心配はいりません。 冒頭で\catcode`\*=\activeとして実際に文書を作成してみましょう。

ただしこの実装だと、同じ行に「*」が二回出てくるとおかしなことになったり、あとに何かしら段落が存在しないと意図しない結果になったりします。 本当ならもっと作りこむべきなのでしょうが、そもそも軽量マークアップ言語なんて制作者の技術的な都合で仕様が決まるものなんだから、ここはそういう仕様ということにして先に進みます。

Re:VIEWのインラインコマンド

Re:VIEWには@<command>{content}という形式のインラインコマンドがあります。 これを同様にアクティブ文字を濫用して実装してみましょう。

\begingroup
\catcode`\@=\active

\gdef\codereview{code}
\gdef\bfreview{b}

\gdef@<#1>#2{%
  \def\reviewname{#1}
  \ifx\codereview\reviewname\texttt{#2}\fi
  \ifx\bfreview\reviewname\textbf{#2}\fi}
\endgroup

こちらはTeXの記法に近い(?)ので比較的安直に実装できます。 上記では等幅にするコマンド(@<code>{...})と太字にするコマンド(@<b>{...})だけを定義していますが、必要に応じて好きなものを追加してください。

章見出しや節見出し

Re:VIEWでは「=」で行を書き始めると個数に応じて階層的なヘッダになります。 これをTeXで実装しましょう。めんどくさいですが、処理自体は素直なものです。

\begingroup
\catcode`\==\active
\gdef=#1#2{\let\@tmpa#1\let\@tmpb#2%
  \ifvmode \@headertrue\inc@header@cnt
    \ifcat\noexpand=\noexpand#1 \inc@header@cnt\let\@tmpa\relax
      \ifcat\noexpand=\noexpand#2 \inc@header@cnt\let\@tmpb\relax
  \fi\fi\fi
  \eq@protected\@tmpa\@tmpb}
\endgroup

\newif\if@header
\newcount\header@cnt
\def\inc@header@cnt{\global\advance\header@cnt by 1}
\def\reset@header@cnt{\global\header@cnt=-1}

\reset@header@cnt
\def\eq@protected{\if@header\proc@header\else =\fi}
\def\proc@header{%
  \expandafter\gen@header\header@cnt}
\def\gen@header#1{\@headerfalse%
  \ifcase #1 \review@chapter
  \or        \expandafter\review@section
  \or        \expandafter\review@subsection
  \fi\reset@header@cnt}
\def\review@chapter#1\par{\edef\chapstring{#1}\chapter[]{\chapstring}}
\def\review@section#1\par{\edef\sectstring{#1}\section[]{\sectstring}}
\def\review@subsection#1\par{\edef\subsectstring{#1}\subsection[]{\subsectstring}}
現状だとページの柱や目次に章タイトルを出力できないなどの問題は残っていますが、とりあえずできたということにします。
見出し行があるだけでずいぶんマークアップ言語っぽくなりますね。

Re:VIEWの環境

Re:VIEWでは//foo{から//}のような書式で特殊なスタイルのための環境を設定できるようになっています。 これもLaTeXの環境の記法に似ているので簡単に実現できるかなと思ったんですが、そもそもTeXには真のパターンマッチがないので、ややトリッキーな仕掛けが必要でした。

\begingroup
\catcode`\/=\active
\gdef//#1#{\begingroup\catcode`\/=\active\def//{}
  \csname review@#1\endcsname}
\endgroup

\long\def\review@list#1{\begin{alltt}#1\end{alltt}\endgroup}
\long\def\review@quote#1{\begin{quote}#1\end{quote}\endgroup}
\long\def\review@read#1{\begin{quote}#1\end{quote}\endgroup}
\def\review@footnote#1{\footnote{#1}\endgroup}

ここでちょっと悩ましいのが、よく似た記法を持つ//footnoteのようなRe:VIEWコマンド(波カッコがない点に注意)の存在です。これにも対応するには本気でパーザを書くことになりそうなので、//footnoteコマンドでもコンテンツは波カッコで囲むということにします。 つまり、この時点でRe:VIEWとは互換性のないシンタックスになってしまっていますが、軽量マークアップ言語なんて制作者の技術的な都合で仕様が決まるものなんだから(ry

あとなんかallttの中の改行処理がうまくいってないとか、入れ子への対応が不十分とか、課題は残ってるけど深追いしない。

Re:VIEWっぽい原稿をデフォルトでロードするTeXプログラムを作る

これらの定義をプリアンブルに書いたりスタイルファイルに書いたりして、LaTeXの \begin{document} ... \end{document} の間で実行するだけでも面白いといえば面白いのですが、どうせなら、.reファイルから直接PDFを組版できる独立したコマンドがあると便利ですよね。 というわけで、上記のマクロたちをフォーマットとしてまとめておきました。

revtex: TeX with Re:VIEW syntax
https://github.com/k16shikano/revtex

いちおう補足しておくと、TeXの文脈でフォーマットといったら、initexを使ってダンプする(あるいはダンプした)ファイルのことです。 そのフォーマットをデフォルトで利用するrevtexという新しいTeXの実行ファイルを作ることで、Re:VIEWっぽい記法の原稿を直接コンパイルできるようにしようというわけです。

日本語を組版したいので、ベースにするのはuplatexコマンドとします。 uplatexの実行ファイルをrevtexという別名で用意し、上記のフォーマットをかませて使うように設定すれば、こんなふうにTeXで直接、ほぼRe:VIEW記法の原稿をコンパイルできるようになります。

$ ls -la /usr/bin/revtex # revtexはuplatexのシンボリックリンク
lrwxrwxrwx 1 root root 16 Dec 22 12:28 /usr/bin/revtex -> /usr/bin/uplatex
$ cat sample.re          # sample.reは(ほぼ)Re:VEIW記法のファイル
= はじめてのUNIX

== 実際すごい

重金属を含んだ酸性雨が降りしきるなかをものともせず、
@<b>{マグロツェッペリン}//footnote{巨大飛行船}が回遊する!

* ネオサイタマ
* マルノウチ・スゴイタカイビル

その頂から退廃的な高密度ネオン看板が瞬く地獄めいた都市の喧噪を見下ろす影がひとつ急降下した。コワイ!

== もっとすごい

「こんにちはニンジャ・スレイヤー=サン。」
そういって敵は姿を見せぬまま@<code>{UNIX}端末にログインした。

= インガオホー

こんにちはダークニンジャ=サン。ハイクを詠め!

//quote{
トチノキ、フユコ……
}

#@# fin
$ revtex sample.re       # ほぼRe:VIEWな原稿がTeXでコンパイルされる
This is e-upTeX, Version 3.14159265-p3.6-u1.20-141210-2.6 (utf8.uptex) (TeX Live 2015/Debian) (preloaded format=revtex)
 restricted \write18 enabled.

kpathsea: Running mktexfmt revtex.fmt
...

いうまでもありませんがRubyもRe:VIEWも不要です。最後にdvipdfmxが何か言ってますが、無視する方向で。 生成されたPDFを以下に張っておきます。

画期的ですね。

実は、少なくともひとつ、どうにも解決できないダサい制限があって、原稿ファイルの末尾にオリジナルのRe:VIEWではコメントとして無視される「#@# fin」という行を書いておく必要があります。 TeXは組版をするとき、\endというプリミティブで原稿ファイルの終端に到達したことを知るのですが、Re:VIEWにはそのための記法がないので、こうしてお茶を濁しているわけです。

(追記) と思い込んでいたら、e拡張には\everyeofなるそのまんまなプリミティブがあると教えてもらいました。 これを使うと、確かに最後の行が不要になるので、ひそかにあきらめていた行コメントも実現できました。(追記おわり)

免責と今後の展望

auxによる参照解決とか、エスケープとか、いろいろさぼってるので実用品ではありません。 また、これ以上Re:VIEW対応率をあげようとか、バグを直そうとか、そういう予定もたぶんありません。 むしろ、あらためてMarkdownっぽいのを実装するほうが面白そうかも。

参考資料

TeX by Topic
TeX芸には欠かせない説明不要の名著。日本語訳もあるが入手は困難。原著者のサイトで英文なら全部読める。
1TeXの実装
TeX芸の北極。文字「1」をアクティブ文字にすることで、文字通り「1」のみでTeXコンパイル可能な文書を作る。
xmltexの実装
XML文書をTeXでコンパイルするという、海外のTeX芸のひとつ。
Re:VIEWフォーマットのドキュメント
これ以外にもいろいろ隠しコマンドがあるらしい。

2015/09/24

『あなたの知らない超絶技巧プログラミングの世界』は誰が読むべきか

遠藤侑介さんといえば、Quineをはじめとする変態プログラムの世界的なタツジンとして有名ですが、そのむかし遠藤さんに向かって「Quineの本とか、売れないことが確実ですね」という趣旨の発言をしたことがあります。遠藤さんがブログやコンテストで発表していた変態プログラムには個人的にとても魅力を感じていて、翻訳書で一緒にお仕事をする前から楽しませてもらっていたのですが、さすがに書籍の企画ネタにするのは難しいなあ(売れるようにするのが難しいという意味で)と思っていたのです。それから数年後、まさか本当にQuineの書き方の解説が載っている本が出版されるなんて! それもQuineのみならず、遠藤さんのネタを徹底解説するような本がでるなんて! 企画を担当した編集者もずいぶんな変態に違いありません。というわけで、今月発売された遠藤侑介著『あなたの知らない超絶技巧プログラミングの世界』という本をさっそく読みました(下のリンクはアマゾンで、9/24現在ではまだ予約中だけど、なぜか都内の大型書店にはふつうに配本されている)。

読んだといっても、ざっと目を通したレベルであって、内容をきちんと咀嚼できるほどには読み込んでいません。というか、本書の内容をきちんと咀嚼できる日が自分の人生にやってくるのだろうか、というのが率直ないまの気持ちです。なにせ本書は、いうなればリストやパガニーニが懇切丁寧に自分の楽器演奏テクニックを言語化して解説してくれているようなものです(実際、本書のタイトルの「超絶技巧」はリストの同名の練習曲に由来するようです)。あるいは、シューマッハが自分のドライビングテクニックを教本としてまとめてくれているようなものです。そんなもの、本を読んだくらいで習得できるわけがないじゃないか! その意味では、この本、けっして「わかりやすい」とは言えないと思います。むしろ「わからない」ことをわざわざ楽しむための本なので、「わかりやすくない」のが必然なんでしょう。解説自体はとても丁寧に書かれているので、必要になったときに必要な箇所を真剣に読めば大丈夫そうだなと判断して順調に読み飛ばしました。にしても、この本の内容が「必要になるとき」なんて自分にあるんだろうか……。(という読者の葛藤を見越して「必要になるとき」を強制発動するための「練習問題」がついているところに著者の心意気を感じました。)

「この本が必要なのは誰だろう」という、おそらく書籍企画にとって根源的な問題は、著者の遠藤さんをだいぶ悩ませたんではないかと思います。本文を読んでいると「実益は期待しないで」といった趣旨の開き直りにちょくちょく出くわすし、「まえがき」に至っては「実用性という観点は雑念」とまで言い切られています。でも、「雑念」だと言った鼻の先が乾かないうちに「ある種の気づきを与えてくれる」とか言って実用性がほのめかされています。

じゃあ、この本、いったい誰が読むべきなんでしょうか? 独断ですが、本書の対象読者は大きく次の3つに設定できる気がします。

1. 超絶技巧なプログラムをでたい人
たぶんこの本のいちばんありがちな楽しみ方は「めでる」でしょう。実際、第1章は超絶技巧プログラムを眺めて楽しむという位置づけだし、後続の章も眺めているだけで楽しくなります。『Core Memory ― ヴィンテージコンピュータの美』なんかと同様に、計算機とその周辺にある種の美を感じる人はとりあえず購入して損はしないはずです。
2. 超絶ではないにせよプログラミングの技巧に興味がある人
この本は、Quineのようなプログラムを書きたい人だけでなく、ある種の技巧的なプログラムを書きたい人にとってはそこそこ実用的です。たとえば、CUIのアプリでアニメーションをする方法のような実用的で具体的な内容が丁寧に解説されている本は、ほかにあまりない気がします。また、zlibを使わずにPNGを作る例など、プログラミングに必要な潔さ(教科書には書いていない)を学べます。プログラミングコンテストとかで応用できたりできなかったりする気がします。出たことがないので憶測です。
3. 計算機科学とか数学基礎論が好物な人
数学基礎論や計算機科学の深めの話に踏み込んだコラムの数々が実に有益な読みどころです。Quineの存在証明をRubyで書き下してくれている本なんて、たぶん世界中でほかにはなかったし、これからもないと思います。デュードニーの『チューリングオムニバス』とか、まだ翻訳が出ていないけど『Good Math: A Geek's Guide to the Beauty of Numbers, Logic, and Computation (Pragmatic Programmers)』とかが大好きな人はコラムだけでも興奮できると思います。

無理やりまとめると、本書は(ほぼ)世界一の人がそのテクニックを披露し、伝授してくれて、さらに深堀するという貴重な本です。遠藤さんが書いたこの本を読みたい人は世界中に少なからずいるでしょう。いまのところ本書は日本語でしか楽しめないので、日本語ネイティブで本当によかった。9月28日にはジュンク堂池袋店でサイン会もあるそうなので、Quineなサインをもらいにいこうと思います。

なお、全体を通してRubyがメインで使われているので「Ruby限定の内輪テクニック集」に見えるかもしれませんが、それに終始する本ではないのはさすが遠藤さんだと思いました。唯一残念なのは索引がないところです(上記の2と3が対象読者なら必須だと思う)。あと細かい話ですが、Paul Grahamのカタカナ表記は「ポール・グレアム」のほうがいいと思いました。

2015/09/10

Wikipediaのエントリを束ねてEPUBを作れるようにしてみた

Wikipediaには好きなページを集めて本を作れる機能があります。左側のメニューにある[印刷/書き出し]から[ブックの新規作成]というメニューをクリックすると、それ以降に閲覧する各ページで「ブッククリエーター」というツールバーが以下のような感じで有効になって、そのツールバーで自分が本に収めたいページを追加していけるという機能です。追加したページを並べて自分だけのオリジナルの本が作れます、というサービスです。

で、何年か前はこのブッククリエーターの出力形式としてPDFのほかにEPUBを選べたのですが(参考)、いつの間にかPDFとプレーンテキストのみになってしまっていてEPUBを作れません。これは日本語版だけでなく英語版でも同様です。

べつにWikipediaをEPUBで読めないからといって困ることはないのですが、自分が開発して自分で使っているEPUB作成ツールのテスト用にWikipediaのページを使えたらいいなと思って、Wikipediaのエントリをいくつか指定してEPUBを生成できる仕組みを作ってみました(参考)。動機が動機なのでローカルでのみ使うつもりだったのですが、AWSでデモが動くようにしてみました(ただしエントリの上限を3つにしているので3章までの本しか作れません。ダウンしてたらごめんなさい。あと英語版Wikipediaのみに対応)。

以下のような感じにEPUBが生成されてダウンロードできるようになるはずですが、Mediawikiのパーズで力尽きたので、WebアプリとしてもEPUBジェネレータとしてもまだぐだぐだです。低品質の勧めに従って公開してみます。