This is fantastic. I was looking into this library and wondering about the particular scenarios where it’s better than nested vectors. Perfect timing
Is there a reason why you prefer to use Word8
with COMPLETE
pattern synonyms instead of an ADT (Dead
| Alive
) with a Storable
instance? If both representations are equally fast, I would prefer the ADT (but they may not be).
Good question! I’m not involved at all in this work, though; I’m just reposting an interesting blog post.
The article does say this:
We use a
Word8
to represent theCellState
here, as this allows us to use the more efficient representation of bothvector
Vector
s andmassiv
Array
s. We could have defined a sum type, or usedBool
as ournewtype
representation instead, but in both cases, this would have meant using boxed representations, which take more space and are less compact in memory[1]. However, this introduces a lot of unnecessary invalid states; we avoid this problem by defining a pair of pattern synonyms, along with aCOMPLETE
pragma to ensure that we get an exhaustive match once we match on both of them.Another reason behind our choice of
Word8
has to do with our need to determine the number of living cells in a neighbourhood quickly. WithWord8
, we can directly sum over representations, as living cells are1
, while dead ones are0
. If we had used a sum type (orBool
), this would involve an additional conversion, whereas in our case, acoerce
is all we need.
I think the first paragraph does overlook the possibility of using storable vectors, but the second point is a good reason to use Word8
over an ADT.
Edit: although, in your storable instance you could of course map Alive → 1 and Dead → 0, which should allow you to do a similar trick for adding up live cells. Then you would have to do some custom peeking which may not be well supported by massiv and vector.