
\section{\label{discussion}Discussion}

     The algorithms described involve state transition in an
essential way, but it is 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 do not 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
did not 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,
together with use of higher order functions.

     The price one pays for this generality is that while all the
programs given in this article are executable, they run too slowly
to be regarded as production simulation programs.  Unless functional
compilers make rapid progress, it is difficult to imagine that {\em exactly}
the kind of programs given here could be competitive in this r\^{o}le
in the immediate future.  Presumably the programs could be
optimised to gain significant factors in speed (and efficiency of
memory utilisation).  Higher order functions could be used
with sparingly, and probably ``granularity'' could be increased
in various ways.  A few efforts were made in this direction,
but these were hindered 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, which they often do better
than compilers, provided they have a reasonably accurate idea of what
goes on during execution.  It is relatively difficult to
form such a mental model for a lazy functional language, but 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.

