453 lines
12 KiB
Plaintext
453 lines
12 KiB
Plaintext
|
%%% This is a LaTeX2e style file.
|
||
|
%%%
|
||
|
%%% It supports setting functional languages like Haskell.
|
||
|
%%%
|
||
|
%%% Manuel M. T. Chakravarty <chak@cse.unsw.edu.au> [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 <keller@cs.tu-berlin.de> 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 <Martin.Erwig@FernUni-Hagen.de> for feedback and
|
||
|
%%% suggestions, and to Conal Elliott <conal@MICROSOFT.com> 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
|
||
|
%%%
|
||
|
%%% \<map
|
||
|
%%% g\>
|
||
|
%%%
|
||
|
%%% 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}\\
|
||
|
}%
|
||
|
}
|
||
|
|
||
|
|