%%% 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.1 2003/12/02 18:07:10 carlier 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}\\
    }%
  }


