Literate programming can be a lot of fun (at least if you like to write prose), but typesetting the resulting document isn't the most enjoyable task in the world. Most source code doesn't typeset well, and marking it up manually misses the whole point of literate programming. There are a few tools that convert source files to TEX sources, but most are rather cumbersome, and, besides, they use LaTEX rather than plain TEX.

lambdaTEX is a tool written entirely in TEX which typesets a literate Haskell 98 script directly, without resorting to any preprocessors. The source code is typeset with proper syntax highlighting for different lexical elements, and common ASCII art is replaced with appropriate mathematical symbols. For example, lambdaTEX will typeset the following nonsense code:

fun :: T1 -> Int -> Int -> Int
fun alpha beta gamma =
    case alpha of
        Alt1 -> beta^2
        Alt2 -> if beta <= gamma then beta else gamma
        _ -> undefined


fun :: T1 → Int → Int → Int
fun α β γ =
    case α of
        ALT1 → β↑2
	ALT2if β ≤ γ then β else γ
	_ → ⊥

(the above HTML code is displayed correctly by Mozilla; other browsers will probably choke on its heavy use of HTML4 Unicode extensions.)

The default style has been borrowed from Chris Okasaki's book Purely Functional Data Structures, but lambdaTeX can be reconfigured easily enough if required.

lambdaTEX does its magic using an almost-complete Haskell lexical analyzer, written in over 1000 lines of TeX code. The only information that it cannot retrieve from the Haskell source code itself is the distinction between function names and other variables (variables are typeset in italic, which is not appropriate for functions.) Therefore, the Haskell source code must be annotated using constructs of the form:

\functions (funA,!funB,funC)

which specifies that “funA” and “funC” are functions, but “funB” is not. The “!” notation usually is not needed, but lambdaTEX knows about all standard prelude functions, so, if you redefine “lines” as a variable (why would you?), you can typeset your program correctly by saying “\functions(!lines)”.

lambdaTEX supports Bird-style literate scripts, as well as an inline Haskell mode for including short fragments of code within sentences, math expressions, etc.

The inline mode is used to typeset a short fragment of Haskell code in the middle of a paragraph, for example when referring to a variable defined within the program, simply by enclosing it in a pair of ASCII quotation mark (") characters. The mode is entered by the quotation character. The lexical analyzer exits when it encounters another quotation mark. Newlines are treated as simple whitespace, and comments are illegal. Because the quotation mark character is reserved, strings cannot appear in the inline mode.

The Bird mode is used to process Bird-style literate scripts. The mode is entered by the greater-than (“>”) character. Note that this is a hack, since, in Haskell, “>” designates literate code only when it appears as the first character on a line. The mode exits when it encounters a blank line. The text is typeset as a separate paragraph, indented by “\hsleftskip” on the left and “\hsrightskip” on the right. The “\beforehs” macro is inserted before the fragment of code and “\afterhs” is inserted after it. The “>” character itself is not displayed.

In both modes, the “\everyhs” macro is inserted immediately after entering the Haskell mode.

Finally, because we've already confiscated “>” as an active character, I have decided to grab “<”, too. In lambdaTEX, “<...>” typesets “...” in an italic font. Of course, the meaning of “<” and “>” is restored within math formulas.

More documentation will follow in the future. For now, let the source guide you.


To see lambdaTEX in action, download “Example.pdf”. It has been generated by running

pdftex Example.lhs

To install lambdaTEX, simply download “lambdaTeX.tex” and put it somewhere in your TEXINPUTS path. It should work with both plain TEX and LaTEX, although I have tested it only with plain TEX.

Note that, if you are going to use lambdaTEX, you may want to grab the latest version from time time, as I am releasing bug fixes and improvement rather frequently in response to the numerous feedback that I have received from the Haskell community. In particular, version 2, which will align declarations under the “::” and “=” symbols, comments under “--” and so on, should be ready before Christmas.

If you have any comments, suggestions, bug reports or bug fixes, I wouldn't mind hearing them. In particular, I'd like to hear of any experiences (good or bad) of using lambdaTEX with LaTEX and with your coding style.

By the way, lambdaTEX is free software covered by a BSDish licence, but, if you use it for typesetting a publication, I would really appreciate if you could drop me a note so I can get an idea of how widely used it is. I would also appreciate an acknowledgment in your publication, but certainly do not require this as a licence condition.

Change History

v1.0 - Initial release.
v1.0.1 - Fixed a bug reported by Jamie Love which caused all guards to be of height 0pt. The guards are now displayed correctly, and guards on consecutive lines are merged into a single vertical line.
v1.0.2 - lambdaTEX now aligns guards correctly even when they do not appear at the beginning of the line, and warns about overful code lines in the same way TEX warns about overful paragraphs, rather than breaking lines randomly. The message displayed for overful lines looks like this:
Overful \hbox (91.3397pt too wide) in Haskell code at line 10
which indicates that line 10 in the source file is 91.3397pt too wide. lambdaTeX will also insert a plain TeX-like black box to the right of any overful line. The width of the box is “\overfullrule”, which defaults to 1ex in plain TEX and 0pt in LaTEX.
v1.0.3 - Fixed a bug reported by Marcin Kowalczyk. lambdaTEX no longer permits breaks after the inline mode if the following character is not a whitespace.
v1.0.4 - The last version of 2001 fixes subscripts to functions that went missing in 1.0.3. Yet another bug report brought to you by Marcin “Qrchak” Kowalczyk. ;)
v1.0.5 - Fixed a bug with line (“--”) comments.