Well, a couple of ideas. I'm not an expert in FP, but...
It's fairly clear we should have a type
Board which represents a game state. The basis of the implementation should be an
evolve function of type
evolve :: Board -> Board; meaning it produces a
Board from applying the rules of the game to a
How should we implement
Board should probably be an n x m matrix of
Cells. We could implement a function
cellEvolve of type
cellEvolve :: Cell -> [Cell] -> Cell which given a
Cell and its neighboring
Cells calculates the
Cell state in the next iteration.
We should also implement a
getCellNeighbors function which extracts a
Cells neighbors from a
Board. I'm not entirely sure of the signature of this method; depending on how you implement
Board you could have for instance
getCellNeighbors :: Board -> CoordElem -> CoordElem -> [Cell], which given a Board and two coordinates (
CoordElem would be the type used to index positions in a
Board), gives you a variable length list of the neighbors (not all cells in the board have the same number of neighbors- corners have 3 neighbors, borders 5 and everyone else, 8).
evolve can thus be implemented by combining
getCellNeighbors for all cells in the board, again the exact implementation will depend on how you implement
Cell, but it should be something like "for all cells in the current board, get their neighbors and use them to calculate the new board's corresponding cell'. This should be possible to do with a generic application of those functions over the whole board using a "map over board's cell function".
You should really implement
cellEvolve so that it takes as a parameter a type
GameRules which encodes the rules of the game- say a list of tuples
(State,[(State,NumberOfNeighbors)],State) which says for a given state and the number of neighbors in each state, which should be the state in the next iteration.
cellEvolve's signature could then be
cellEvolve :: GameRules -> Cell -> [Cell] -> Cell
This would logically take you to making
evolve :: Board -> Board turn into
evolve :: GameRules -> Board -> Board, so that you could use
evolve unchanged with different
GameRules, but you could go a step further and make
cellEvolve pluggable instead of
getCellNeighbors you could also make
evolve generic with regards to the
Board's topology- you could have
getCellNeighbors which wrap around either board's edges, 3d boards, etc.