A program to evaluate Haskell code within LaTeX
Daniel Díaz
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.
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
.
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.
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.
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}
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}
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.
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.
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:
hatex
, iohatex
,
and evalhaskell
commands and environments. When the enclosed expression is
evaluated, its result will be stored in the memo tree (the structure haskintex uses
internally to store pairs of unevaluated code and its result). The next time the same
expression is found, if it is marked with memo
as well, it won't be evaluated again:
the stored result will be used instead.
memo
.
It will force a given Haskell expression to be evaluated every time, not using the memo tree.
memo
option everywhere it can be applied,
except for those places where the notmemo
option has been specified.
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.
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.
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
.
autotexy
: Apply the function texy
from the
Text.LaTeX.Base.Texy
module of the HaTeX package to every expression in a hatex
or iohatex
command. This effectively allows the user to write expressions in types other than LaTeX
and have haskintex to perform the required transformation.
debug
: Only for debugging purposes. It writes a file with extension .debughtex with the
AST of the internal representation of the input file haskintex uses.
help
: Show the version of the program and some information, like usage and
a description of the different flags.
keep
: Do not remove the auxiliary module after the program ends.
The name of the auxiliary module is the name of the input file preceded by Haskintex_
.
lhs2tex
: By default, haskintex uses basic LaTeX verb
and verbatim
declarations for Haskell code. When this flag is enabled, the output
will be formatted for lhs2TeX.
manual
: This flag will make haskintex write evalhaskell
and writehaskell
outputs unchanged. In other words, no verb
,
verbatim
, or code
(in case the lhs2tex flag is enabled) declarations
will be used.
memo
: Unless otherwise specified, every evalhaskell
, hatex
or iohatex
command (or environment) will be called with the memo
option.
memoclean
: Cleans the memo tree after the execution of haskintex. If
several files are processed, the memo tree will be cleaned after processing all of
them. Read more about the memo tree in the Memorization section.
nosandbox
: Do not use the sandbox package db even if haskintex is running
in one.
overwrite
: Overwrite the output file if it already exists. If this flag
is not set, the program will ask before overwriting.
stdout
: Instead of writing the final output to a file, send it to the standard
output stream (usually, the screen), making possible to redirect the output to another application.
verbose
: While working, print information on the screen about the execution.
visible
: Make Haskell code in writehaskell
environments visible by default.
The code of haskintex is hosted on GitHub. For suggestions, bug reports, or any other concern, fill an issue at the Issue Tracker.