There were some fairly obvious algorithmic complexity improvements to my solution, but nothing available immediately from Haskell's standard library.
My basic approach uses only pure immutable data structures.
The infinite world is a map, which in standard Haskell are backed by binary trees ordered by the key. I took those keys to be n-ary vectors. So to find whether a point is active, I just test to see if its vector is in the map.
To compute the numbers of neighbours, I translated the map in all the unit directions, and merged them with addition, starting at 1. The result is that, if you look up a vector in the map, it'll tell you the number of adjacent active points.
I then went through neighbourhood map and for each key value pair, tested whether the key is in the original. I then use this information with the count to decide whether to stay active or go inactive.
The merges are algorithmically fast, since they use a hedge union, but I only get to do that when combining the translated maps. The main update still does a full map lookup for every cell with a non-zero number of neighbours. Worse, translating the maps is horrible, because adding a vector to all the keys will completely screw up the (lexicographic) ordering, meaning that the tree has to be rebuilt.
For a second attempt, I used a trie, where you use the first component of the vector as a key to lookup another trie. You then use the second component of the vector to lookup another trie. And so on, until you've exhausted the vector. So it's a bunch of nested maps:
Code:
data Trie k a = Value a
| Map (M.Map k (Trie k a))
deriving (Functor, Foldable)
Translating such a trie doesn't mess with any structure, so it can be done very fast just by mapping over the keys. Next, I used a special purpose merging function so that I could combine the neighbourhood counts with the original map as a hedge merge. The solution then does absolutely no lookups. Everything is just hedge merges and mapping over the keys.
It does 4 dimensions in 0.14s, 5 dimensions in 4s and copes with 6 dimensions in 90s.