HaskinTeX

A program to evaluate Haskell code within LaTeX

Daniel Díaz

The haskintex program

The haskintex program is a tool that reads a LaTeX file and evaluates Haskell expressions contained in some specific commands and environments. It allows you to define your own functions, use any GHC Haskell language extension and, in brief, anything you can do within Haskell. You can freely add any Haskell code you need, and make this code appear optionally in the LaTeX output. It is a tiny program, and therefore, easy to understand, use and predict.

Installation

To install haskintex from Hackage, use the cabal program:

? cabal update
? cabal install haskintex

This will update your package database and install the latest version of haskintex. Otherwise, you can build the current developing version downloading its code as a zip file.

Note that this page will be updated with every new version released to Hackage, so it reflects the features of the last released version. If you have a previous version, some of the features explained here may not apply to you. To check what version you have installed, run haskintex -help.

How does it work?

Consider the following simple example.

\documentclass{article}
\begin{document}
I have \evalhaskell{2+3} fingers in my right hand.
\end{document}

If the above LaTeX code is written in foo.htex, after running haskintex foo.htex the file foo.tex will be written with:

\documentclass{article}
\begin{document}
I have \verb`5` fingers in my right hand.
\end{document}

The Haskell code 2+3 has been evaluated to 5, and the result has been enclosed in a verb command. The evaluation is done using GHC, so it must be installed in order to use haskintex.

The file foo.htex can be processed running hakintex foo as well. When the given input file does not exist, haskintex adds the .htex extension automatically. If the file with the added extension does not exist, it throws an error.

Let's go through another example. The factorial function can be implemented recursively in Haskell.

fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n-1)

To include this function in the scope of evalhaskell use writehaskell as shown below.

\documentclass{article}
\begin{document}
\begin{writehaskell}
fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n-1)
\end{writehaskell}
While 5 factorial is \evalhaskell{fact 5}, 10 factorial is
\evalhaskell{fact 10}.
\end{document}

Therefore, to add binding definitions use the writehaskell environment, and to evaluate code use evalhaskell. If the output of an evaluation is known to be big and it is not desired to be inlined, use evalhaskell as an environment instead. For example:

\documentclass{article}
\begin{document}
This is the list of numbers from 1 to 1000:
\begin{evalhaskell}
[1..1000]
\end{evalhaskell}
\end{document}

Lines in the output of evalhaskell as environment are bounded to 60 characters. A line break will be introduced if this number is exceeded.

Using HaTeX

It is possible to use any Haskell type within the evalhaskell command or environment. Whatever the result is, it will be added to the LaTeX output using the Show instance given by the type of the input expression. Sometimes, this is good enough, but probably you will end up wanting a more complex way to display your results. To approach this problem, there is a library called HaTeX which defines a LaTeX type. Using this library, you can define your own functions from and to this type. In the other hand, haskintex lets you use the command hatex. This command receives as input a Haskell expression of type LaTeX and generates its corresponding LaTeX code as output. It is recommended to take a look at the HaTeX library to make yourself an idea of the possibilities you have. As an example, this is how you draw a portion of a logarithmic spiral.

\documentclass{article}
\usepackage{tikz}
\usepackage[utf8]{inputenc}
\author{Daniel Díaz}
\title{Embedding HaTeX in \emph{haskintex}}
\begin{document}
\maketitle
Below is the \emph{Spira Mirabilis} inserted using the HaTeX
package.
\begin{writehaskell}
import Text.LaTeX
import Text.LaTeX.Packages.TikZ.Simple

spiral :: Figure
spiral = LineWidth (Pt 2) $
    pathImage 0.01 (0,4) $
      \t -> ( a * exp t * cos (b*t)
            , a * exp t * sin (b*t)
              )
  where
    a = 0.1 ; b = 4
\end{writehaskell}
\hatex{center $ tikzpicture $ figuretikz spiral}
\end{document}

The output looks like this:

The example above uses functions from the Text.LaTeX.Packages.TikZ.Simple module, which deals with graphic generation using TikZ scripts. You may take a look to its API documentation to fully understand the given example.

Using HaTeX with IO

While the hatex command opens tons of possibilities to generate LaTeX code, it suffers from an unfortunate restriction. Since it only accepts expressions of type LaTeX, it will never accept an expression that performs IO computations. To solve this, use the iohatex command. It works the same way as the hatex command does, but it expects an expression of type IO LaTeX instead. Here an example:

\documentclass{article}
\begin{document}
\begin{writehaskell}
import Text.LaTeX
import Data.Time (getCurrentTime)
import Control.Applicative ((<$>))
import Data.String (fromString)
\end{writehaskell}
I am testing the \texttt{iohatex} command when the time is \iohatex{fromString . show <$> getCurrentTime}.
\end{document}

Including Pragmas

If you include pragmas with the writehaskell environment and run haskintex with the keep flag, you will notice that the pragma is included below the module ... where clause, and therefore it is not working. To include pragmas, use the haskellpragmas environment. It would go like this:

\documentclass{article}
\begin{document}
\begin{haskellpragmas}
{-# LANGUAGE OverloadedStrings #-}
\end{haskellpragmas}
\begin{writehaskell}
import Text.LaTeX

overloaded :: LaTeX
overloaded = "This is an Overloaded String."
\end{writehaskell}
\hatex{overloaded}
\end{document}

Code ordering

The place where evalhaskell is called does not really matter. The function fact can be called before defining it.

\documentclass{article}
\begin{document}
While 5 factorial is \evalhaskell{fact 5}, 10 factorial is
\evalhaskell{fact 10}.
\begin{writehaskell}
fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n-1)
\end{writehaskell}
\end{document}

Note that this also applies to pragmas. If you include a pragma at the end (see below), it will still apply to the Haskell code.

\documentclass{article}
\begin{document}
\begin{writehaskell}
import Text.LaTeX

overloaded :: LaTeX
overloaded = "This is an Overloaded String."
\end{writehaskell}
\hatex{overloaded}
\begin{haskellpragmas}
{-# LANGUAGE OverloadedStrings #-}
\end{haskellpragmas}
\end{document}

What haskintex does is to traverse the LaTeX code twice. The first time it creates a Haskell module with all the code defined with writehaskell and haskellpragmas environments, placing the pragmas at the beginning of the file. In the second pass, it evaluates all the evalhaskell calls with the created module imported. Note that this means you have to avoid duplicated names.

Visibility

By default, the Haskell code introduced by writehaskell (or haskellpragmas) will not show up in the processed LaTeX code. To change this, use the visible option. For example:

\documentclass{article}
\begin{document}
\begin{writehaskell}[visible]
fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n-1)
\end{writehaskell}
While 5 factorial is \evalhaskell{fact 5}, 10 factorial is
\evalhaskell{fact 10}.
\end{document}

A verbatim environment will contain the code. To change the default behavior and make Haskell code visible by default, pass the -visible flag when invoking haskintex. Use then the hidden option to hide specific calls to writehaskell (or haskellpragmas).

\documentclass{article}
\begin{document}
\begin{writehaskell}[hidden]
fact :: Int -> Int
fact 0 = 1
fact n = n * fact (n-1)
\end{writehaskell}
While 5 factorial is \evalhaskell{fact 5}, 10 factorial is
\evalhaskell{fact 10}.
\end{document}

You can still use the visible option but it will be pretty much useless. However, it may be useful if you are switching the -visible flag on and off frequently.

Memorization

You can tell haskintex to remember the value of an expression to avoid compute it twice. This, however, has a drawback: the expression won't be evaluated again, even if its actual value changes. These are the tools you can use to control this feature:

To sum up: place the memo option to those expressions whose value don't change over time and you don't want to compute twice. And let haskintex do the rest. Alternatively, use the memo flag and apply the notmemo option to those expressions whose value may change over time.

Sandboxes

If haskintex is running inside a cabal sandbox environment, it will use the sandbox package db when evaluating Haskell code. If you don't want this to happen, use the -nosandbox flag and the sandbox package db will be ignored.

Flag reference

Below a list of the flags accepted by the program. Any argument starting with - will be recognized as a flag, even if it is not defined (in which case, it will have no effect). Anything else will be considered an input file. For instance, this is a valid invocation to process the file foo.htex verbosely: haskintex foo -verbose.

Code repository

The code of haskintex is hosted on GitHub. For suggestions, bug reports, or any other concern, fill an issue at the Issue Tracker.