code • words • emotions

Daniel Janus’s blog

The TeX Hackery

6 April 2008

After a longish while of inactivity, I finally got around to finishing the draft spec of a next-generation protocol for Poliqarp, the be-all-end-all corpus concordance tool that I maintain. The spec is being written in LaTeX, and it has a number of subsections that describe particular methods of the protocol. Each one of those is further divided into sub-subsections that describe the method’s signature, purpose, syntax of request, syntax of response, and an optional example. I thought to write a couple of macros to help me separate the document’s logic from details of formatting, so that I could say:

\synopsis/() -> {version : int; extensions : string*}/

and have it expanded into:

\paragraph{Synopsis}
\verb/{version : int; extensions : string*}/

Being a casual LaTeX user who hardly ever writes his own macros, I first thought to use LaTeX’s command-defining commands, \newcommand and \renewcommand. However, I quickly ran into the limitation that the argument of commands defined in such a way can only be delimited by curly braces, which I could not use because they might appear in the argument itself.

I googled around and found that this limitation can be overcome by using \def instead, which is not a LaTeX macro but rather an incantation of plain TeX, and allows to use arbitrary syntax for delimiting arguments. Having found that, my first shot was:

\def\synopsis/#1/{\paragraph{Synopsis}\verb/#1/}

which, obviously enough, turned out not to work, producing errors about \verb ended by an end-of-line.

“What the heck?” I thought, and resorted to Google again, this time searching for tex macros expanding to verb. This yielded an entry from some TeX FAQ, which basically states that the \verb is a “fragile” command, and as such it cannot appear in bodies of macros. Ook. So it can’t be done?

“But,” I thought, “TeX is such a flexible and powerful tool, there must be some way around this!” And, as it would turn out, there is. Yet more googling led me to this thread on comp.text.tex, where someone gives the following answer for a similar question:

\def\term#{ %
   \afterassignment\Term \let\TErm= }%

\edef\Term{\noexpand\verb \string}}

Now this is overkill. Why in the world am I forced to stuff such incomprehensible hackery into my document just to perform a seemingly simple task?! Easy things should be easy — that’s one of the principles of good design.

Reluctantly, I copied it over, and attempted to adjust it to my needs. After a number of initial failed attempts, I thought that I might actually attempt to understand what all these \afterassignment’s, \noexpand’s and \edef’s are for, so I downloaded the TeXbook and dived straight in.

I spent another fifteen minutes or so reading bits of it and trying to understand tokens, macros, when they are expanded and when merely carried over, etc. But a sparkle of thought made me replace the whole complicated thingy with a simple snippet that actually worked.

\def\synopsis{\paragraph{Synopsis}\verb}

That’s right. This superficially resembles a C preprocessor macro, and works because I was lucky enough to have \verb appear last in the definition, thus allowing the “arguments” of \synopsis to be specified just like arguments to \verb and fit at exactly right place. I’m almost certain that it does not always work this way, but for now it’ll suffice.

Oh well. TeX is undoubtedly a fine piece of software that provides splendid results if used right. But I can’t get over the impressions that there are a great deal more idiosyncracies like this in it than in, say, Common Lisp, even though the latter’s heritage tracks back to as early as 1958 and is a whopping twenty years longer than TeX’s. (On the side note, as it turns out, someone has already written a Lisp-based preprocessor for TeX macros. Gotta check it out someday.)

As for the TeXbook itself: it is a fine piece of documentation that I will definitely have to add to my must-read list, though it admittedly has a math-textbookish feel to it. First, however, I want to finish “Shaman’s Crossing” by Robin Hobb (which I will probably brag about in a separate post once I’m finished with it) and tackle Christian Queinnec’s “Lisp in Small Pieces”.