%%% This is a LaTeX2e style file. %%% %%% It supports setting functional languages like Haskell. %%% %%% Manuel M. T. Chakravarty [1998..2000] %%% %%% $Id: haskell.sty,v 1.2 2004/05/16 08:20:09 dons Exp $ %%% %%% This file is free software; you can redistribute it and/or modify %%% it under the terms of the GNU General Public License as published by %%% the Free Software Foundation; either version 2 of the License, or %%% (at your option) any later version. %%% %%% This file is distributed in the hope that it will be useful, %%% but WITHOUT ANY WARRANTY; without even the implied warranty of %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the %%% GNU General Public License for more details. %%% %%% Acknowledegments ========================================================== %%% %%% Thanks to Gabriele Keller for beta testing and %%% code contributions. Thanks to the LaTeX3 project for improving the LaTeX %%% sources (which helped me writing this code). Furthermore, I am grateful %%% to Martin Erwig for feedback and %%% suggestions, and to Conal Elliott for pointing out %%% a tricky bug. %%% %%% TODO ====================================================================== %%% %%% B ~ bug; F ~ feature %%% %%% * F: Along the lines of the discussion with Martin Erwig add support for %%% keywords etc (see the emails) %%% %%% * B: If we have as input %%% %%% \ %%% %%% there won't be a `\hsap' inserted!! (Can this be solved by using %%% \obeylines in \<...\>?) %%% %%% * B: A \relax is needed after a & if it immediately followed by a \hsbody{} %%% (See TeXbook, S.240) %%% %%% * F: Implement a \hstext{...} as \(\text{...}\). %%% %%% * We would like hswhere* etc that are like haskell* (\hsalign already %%% supports this, ie, there is a \hsalign*). %%% %%% * Star-Versions of if, let etc that use a single line layout (maybe not %%% with star, because of the above). %%% %%% * Support for enforcing and prohibiting breaks in `haskell' displays. %%% %%% * Comments in a let-in should be aligned in the same way for the bindings %%% and the body. %%% %%% * It would be nice to have different styles (indentation after in of %%% let-in or not) etc; either to be set with a package option or in the %%% preamble (the latter probably makes more sense). %%% %%% * Literate programming facility: Variant of the `haskell' env (maybe %%% `hschunk', which is named and can be used in other chunks). But maybe %%% it is not necessary to provide a chunk-based reordering mechanism, %%% because most of the Haskell stuff can be in any order anyway... %%% Important is to provide a way to define visually pleasing layout %%% together with the raw Haskell form for program output. (Maybe `haskell*' %%% as Haskell env that outputs its contents?) %%% %% Initialization %% ============== \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{haskell}[2000/10/05 v1.0e Chilli's Haskell Style] %% Parameters %% ========== \newskip\hsmargin \hsmargin\leftmargini %% Main macros and environments %% ============================ % applications % \newcommand{\hsap}{% % application by juxtaposition \unskip\mskip 4mu plus 1mu} % only the last \hsap counts % commands to start and stop setting spaces as \hsap % {\obeyspaces\gdef\@hsSpaceToApp{\obeyspaces\let =\hsap}} % spaces matter!!! {\obeyspaces\gdef\@hsNormalSpace{\let =\space}} % commands to start and stop treating numbers specially, ie, we don't want % them to be affected by font changing commands in Haskell contexts as this % would give italic numerals; the trick is to redefine their math code such % that they go into math class 0 and thus don't change families (cf. `The % TeXbook', Chapter 17, pp152) % \newcommand{\@hsRmNumbers}{% \mathcode`0="0030 \mathcode`1="0031 \mathcode`2="0032 \mathcode`3="0033 \mathcode`4="0034 \mathcode`5="0035 \mathcode`6="0036 \mathcode`7="0037 \mathcode`8="0038 \mathcode`9="0039 } \newcommand{\@hsNormalNumbers}{% \mathcode`0="7030 \mathcode`1="7031 \mathcode`2="7032 \mathcode`3="7033 \mathcode`4="7034 \mathcode`5="7035 \mathcode`6="7036 \mathcode`7="7037 \mathcode`8="7038 \mathcode`9="7039 } % Save the bindings of the standard math commands % % This is somewhat subtle as we want to able to enter the original math mode % within Haskell mode and we have to ensure that the different opening % commands are matched by the correct versions of the closing commands. % \let\@hsmathorg=\( \let\@hsmathendorg=\) \let\hs@crorg=\\ \newcommand{\@hsmath}{% \relax\hbox\bgroup \@hsNormalSpace \@hsNormalNumbers \let\(=\@hsmathorgx \let\)=\@hsmathend \def\\{\hs@crorg}% \@hsmathorg } \newcommand{\@hsmathend}{% \@hsmathendorg \egroup } \newcommand{\@hsmathorgx}{% \relax\@hsmathorg \let\)=\@hsmathendorg } %% Typesetting of Haskell %% ====================== % Inline Haskell phrases are delimited by `\<' and `\>'. % % Note: `\>' is only locally redefined. % \newcommand{\<}{% \@hsmathorg \mathit\bgroup \@hsSpaceToApp \@hsRmNumbers \let\>=\@endhs \let\(=\@hsmath \def\\{\cr} % for Haskell alignments } \newcommand{\@endhs}{% \egroup \@hsmathendorg } % Displayed Haskell (environment `haskell' and `haskell*') % % There are two kind of preambles for \halign: \hs@preambleNorm is for % `amsmath' style alignments and \hs@preambleStar for `equation' style % alignments (but with an unbound number of columns to its right) % % We need #### to get a ## in the \edef building the \halign command. % % first the preambles (also used in \hs@align below): % \def\hs@preambleNorm{% \noexpand\<####\unskip\noexpand\>\hfil&&\noexpand% \<{}####\unskip\noexpand\>\hfil} \def\hs@preambleStar{% \noexpand\<####\unskip\noexpand\>\hfil&\hfil\noexpand% \<{}####\unskip{}\noexpand\>\hfil&&\noexpand\<{}####\noexpand\>\hfil} % % the environments: % \newenvironment{haskell}{% \@haskell\hs@preambleNorm}{% \@endhaskell } \newenvironment{haskell*}{% \@haskell\hs@preambleStar}{% \@endhaskell } % % auxiliary definition getting the preamble as its first argument and starting % the environment: % \def\@haskell#1{% \bgroup \vspace\abovedisplayskip \let\(=\@hsmath % Important when `\(' occurs after `&'! \edef\@preamble{% \halign\bgroup\hskip\hsmargin#1\cr} \@preamble } % % Auxiliary definition ending environment: % \def\@endhaskell{% \crcr\egroup \vspace\belowdisplayskip \egroup\noindent\ignorespaces\global\@ignoretrue% } % single line comment and keyword style % \newcommand{\hscom}[1]{% \relax\(\quad\textnormal{--- #1}\)} \newcommand{\hskwd}[1]{% \mathbf{#1}} % informal description % \newcommand{\hsinf}[1]{% \(\langle\textnormal{#1}\rangle\)} % literals and some special symbols % \newcommand{\hschar}[1]{\textrm'\mathrm{#1}\textrm'} % character literals \newcommand{\hsstr}[1]{"\mathrm{#1}"} % strings literals \newcommand{\hsfrom}{\leftarrow} % <- % aligned subphrases % % check for an optional star and combine prefix (in #1) with one of the two % preambles (with star means to center the material between the first and % second &) % \def\hs@align#1{% \@ifstar {\hs@align@pre{#1\hs@preambleStar}}% {\hs@align@pre{#1\hs@preambleNorm}}% } % % test for optional argument; #1: preamble % \def\hs@align@pre#1{% \@testopt{\hs@align@prealign#1}t} % % got all arguments, now for the real code; #1: preamble; #2: alignment; % #3: body (the material set by the \halign) % \def\hs@align@prealign#1[#2]#3{% \relax\( \edef\@preamble{% \halign\bgroup#1\cr} \if #2t\vtop \else \if#2b\vbox \else \vcenter \fi\fi \bgroup% \@preamble #3% \crcr\egroup% \egroup\) } % % user-level command: alignment without a prefix % \newcommand{\hsalign}{% \relax \hs@align\relax% } % subphrase breaking the surrounding alignment being flushed left % \newcommand{\hsnoalign}[1]{% \noalign{% \hs@align{\hskip\hsmargin}{#1}% }% } % body expression breaking the surrounding alignment % % * setting \hsmargin to 0pt within the preamble (and _after_ it is used in % the preamble) is crucial, as we want \hsmargin only to be applied in % _outermost_ alignments % \newcommand{\hsbody}[1]{% {}\\ \noalign{% \hs@align{\hskip\hsmargin\quad\hsmargin0pt}{#1}% }% } %% Defining commands for use in the Haskell mode %% ============================================= %% %% We use some of the low-level machinery defined in LaTeX's source file %% `ltdefns.dtx'. %% %% \hscommand is similar to \newcommand, but there is no *-version. %% %% We use our own definitions here to insert a strategic `\relax' (see below) %% and to obey spaces within the bodies of Haskell definitions. \newcommand{\hscommand}[1]{\@testopt{\hs@newcommand#1}0} \def\hs@newcommand#1[#2]{% \obeyspaces % spaces count in Haskell macros \@ifnextchar [{\hs@xargdef#1[#2]}% {\hs@argdef#1[#2]}} % All this trouble only to be able to add the `\relax' into the expansion % process. If we don't that, commands without optional arguments when % invoked after an alignment character & don't work properly (actually, the % \obeyspaces doesn't work). I am sure that has to do with the scanning for % \omit etc in \halign (TeXbook, p240), but I don't understand yet why it % is problematic in this case. % % Furthermore, we switch off \obeyspaces in the end. % \long\def\hs@argdef#1[#2]#3{% \@ifdefinable#1{% \expandafter\def\expandafter#1\expandafter{% \relax % in order to stop token expansion after & \csname\string#1\expandafter\endcsname}% \expandafter\@yargdef \csname\string#1\endcsname \@ne {#2}% {#3}}% \catcode`\ =10% % stop obeying spaces now } % Switch off \obeyspaces in the end. % \long\def\hs@xargdef#1[#2][#3]#4{% \@ifdefinable#1{% \expandafter\def\expandafter#1\expandafter{% \expandafter \@protected@testopt \expandafter #1% \csname\string#1\expandafter\endcsname {#3}}% \expandafter\@yargdef \csname\string#1\endcsname \tw@ {#2}% {#4}}% \catcode`\ =10% % stop obeying spaces now } %% Abbreviations %% ============= % infix operators % \newcommand{\hsapp}{\mathbin{+\mkern-7mu+}} \newcommand{\hsifix}[1]{\mathbin{\string`#1\string`}} % let expression % \hscommand{\hslet}[3][t]{% \hsalign[#1]{% \hskwd{let}\\ \quad\hsalign{#2}\\ \hskwd{in}\\ #3 }% } % if expression % \hscommand{\hsif}[4][t]{% \hsalign[#1]{% \hskwd{if} #2 \hskwd{then}\\ \quad\hsalign{#3}\\ \hskwd{else}\\ \quad\hsalign{#4}% }% } % case expression % \hscommand{\hscase}[3][t]{% \hsalign[#1]{% \hskwd{case} #2 \hskwd{of}\\ \quad\hsalign{#3}% }% } % where clause % % * it is important to take the \quad into the preamble, so that nested % \noaligns can break it % \hscommand{\hswhere}[1]{% \hsbody{% \hskwd{where}\\ \hs@align{\quad}{#1}% }% } % do expression % \hscommand{\hsdo}[2][t]{% \hsalign[#1]{% \hskwd{do}\\ \quad\hsalign{#2}\\ }% } %% Extensions for Distributed Haskell (Goffin) %% =========================================== %% %% These definitions may change in the future. \hscommand{\hsunif}{\mathbin{:=:}} \hscommand{\hsalias}{\mathrel{\sim}} \hscommand{\hsoutof}{\twoheadleftarrow} \hscommand{\hsinto}{\twoheadrightarrow} \hscommand{\hsparc}{\binampersand} \hscommand{\hsseq}{\Longrightarrow} \hscommand{\hsex}[2]{{\hskwd{ex} #1 \hskwd{in} #2}} \hscommand{\hsexin}[3][t]{% \hsalign[#1]{% \hskwd{ex} #2 \hskwd{in}\\ \quad\hsalign{#3}\\ }% } \hscommand{\hschoice}[2][t]{% \hsalign[#1]{% \hskwd{choice}\\ \quad\hsalign{#2}\\ }% }