
\section{Discussion}

     The algorithms described involve state transition in an
essential way, but it's doubtful whether their description
would have been any clearer in terms of variables and assignments.
The explicit representation of sequences as infinite lists
seems just as natural.

     The implementations in section \ref{implementations} create an
``array of streams''.  An alternative approach is to create a ``stream
of arrays'', in which each update is performed on the whole lattice to
create a new global state.  It only involves minor changes to the
implementation to create such a stream of arrays
directly.  Alternatively one can feed the results of the given
implementation to a pipeline of \verb$felems$, \verb$transpose$ and
\verb$map (listForm l r)$ to produce a list of arrays.  There are some
advantages to the ``array of streams'' approach (apart from the fact
that it models process-parallelism).  Some existing Haskell
implementations don't handle array accesses very efficiently\footnote{It
seems that functional programming and parallel programming share
this characteristic---if ``array'' is interpretted
as distributed data in the parallel case.  Locality of reference is a
helpful feature of an algorithm for both paradigms}, and in this
approach the array operations are confined to an initial stage where
the streams are ``tied together''.  In the ``stream of arrays''
approach array operations are needed in all updates.  On the other hand
it does seem more natural to have a list of arrays when it comes to
processing the data (the set of configurations) generated by a
simulation.

     In any case, once the ideas about lattices and arrays in section
\ref{lattices} are absorbed, implementation of the three
algorithms is very straightforward.  It was worth the effort of doing
the geometry carefully, for the level of generality it gave in
the implementations.  For example, apart from the definition of
\verb$colour$, the modifications made to the XY model simulation in
section \ref{lgtImplementation} to encompass lattice gauge theory
didn't actually invalidate the code as an implementation of the XY
simulation---the final version works for systems with variables defined
on arbitrary dimension cells of an arbitrary dimension lattice (given
an appropriate instance of the \verb$Cell$ class).
Achieving this level of abstraction depended on
both ordinary (parametric) polymorphism and overloading.

     The price one pays for this generality is that while all
the programs given in this article are executable,
they run much too slowly to be regarded as
production simulation programs.  Unless functional compilers
make rapid progress, it's difficult to imagine that they
can be competitive in this r\^{o}le in the immediate future.
Presumably the functional programs themselves could be optimised
to gain significant factors in speed (and efficiency of memory utilisation).
No major efforts were made in this direction, after a few early attempts,
which were thwarted by difficulty in understanding the behaviour
(in terms of execution speed and memory utilisation) of the programs.
Programmers who need speed are usually happy to invest some effort in
optimising their own codes.  They often do it better than compilers,
provided they have a reasonably accurate idea of what goes
on during execution.  Unfortunately, it's relatively difficult to form
such a mental model for a lazy functional language.  Good profiling tools
may make the job easier\cite{profiling}.

     As they stand, though, the programs capture the
essence of the algorithms in a way that a production FORTRAN
code probably never could.  At the very least, programs like
this must have a r\^{o}le in specification or prototyping.

