
\section{Accessing neighbours}

     The two-dimensional geometry of the problem can be
embodied in the following definitions.
\begin{verbatim}
  type Coord   = (Int, Int)

  neighbs :: Coord -> [Coord]
  neighbs (x, y) = [(x, y + 1), (x, y - 1),
                    (x + 1, y), (x - 1, y)]
\end{verbatim}
\verb$neighbs$ returns a list of sites neighbouring its argument.
The remainder of the code will be independent of the lattice
dimension or shape (in \cite{self} we introduced some more
general techniques for achieving the goal of ``geometry independence'').
We define a specialised \verb$map$-like function for an array, which
operates on a pair-wise, nearest-neighbour basis
\begin{verbatim}
  nns :: (Coord -> Coord -> b -> c) ->
         Array Coord b -> Array Coord [c]
  nns f a =
    array bds [i :=
      [f i j (a ! j) | j <- neighbs i]
              | i <- range bds]
    where bds = bounds a
\end{verbatim}
(In Haskell, \verb$array$ is the array constructor function---it
takes an ``association list'', in which index values are
paired with data by the infix constructor \verb$:=$, and
returns an array.  This can be subscripted by \verb$!$.  It has
the same association between indices and data elements.)

\verb$nns$ is a function which takes a mapping function and
an array, and returns an array in which each element is
a mapped list of the nearest neighbour elements from the
original array.  If $j_1, j_2, ...$ are the neighbours of
site $i$, and \verb$b = nns f a$, then
\newline
\newline
\verb$  b ! $$i$\verb$ ==$
\newline
\verb$      [f $$i$\verb$ $$j_1$\verb$ (a ! $$j_1$\verb$), f $$i$\verb$ $$j_2$\verb$ (a ! $$j_2$\verb$), ...]$
\newline
\newline
Another higher order function we will use is \verb$azipWith$.
\begin{verbatim}
  azipWith f a b =
    array bds [i := f (a ! i) (b ! i) |
                i <- range bds]
    where bds = bounds a
\end{verbatim}
This is analogous to the standard \verb$zipWith$ function on lists.

