We are implementing a matrix compression library based on a modified two dimensional grammar syntax. Now we have two approaches for our data types -which one will be better in case of memory usage? (we want to compress something ;)).
The grammars contain NonTerminals with exactly 4 Productions or a Terminal on the righthand side. We will need the names of Productions for equality checks and grammar minimization.
The First:
-- | Type synonym for non-terminal symbols
type NonTerminal = String
-- | Data type for the right hand side of a production
data RightHandSide = DownStep NonTerminal NonTerminal NonTerminal NonTerminal | Terminal Int
-- | Data type for a set of productions
type ProductionMap = Map NonTerminal RightHandSide
data MatrixGrammar = MatrixGrammar {
-- the start symbol
startSymbol :: NonTerminal,
-- productions
productions :: ProductionMap
}
Here our RightHandSide data saves only String names to determine the next productions, and what we do not know here is how Haskell saves these strings. For example the [[0, 0], [0, 0]] matrix has 2 productions:
a = Terminal 0
aString = "A"
b = DownStep aString aString aString aString
bString = "B"
productions = Map.FromList [(aString, a), (bString, b)]
So the question here is how often is the String "A" really saved? Once in aString, 4 times in b and once in productions or just once in aString and the others just hold "cheaper" references?
The Second:
data Production = NonTerminal String Production Production Production Production
| Terminal String Int
type ProductionMap = Map String Production
here the term "Terminal" is a bit misleading because its actually the production that has a terminal as right hand side. The same Matrix:
a = Terminal "A" 0
b = NonTerminal "B" a a a a
productions = Map.fromList [("A", a), ("B", b)]
and the similar question: how often is the production a saved internally by Haskell? Possibly we will drop the names inside the productions if we don't need them, but we are not sure right now about this.
So lets say we have a grammar with about 1000 productions. Which approach will consume less memory?
Finally a question about integers in Haskell: Currently we are planning on having name as Strings. But we could easily switch to integer names because with 1000 productions we will have names with more then 4 chars (which i assume is 32 bit?). How does Haskell handle this. Is an Int always 32 Bit and Integer allocates memory that it really needs?
I also read through this: Devising test of Haskell's value/reference semantics - but I can't figure out what that exactly means for us - I'm more of a imperative java child then good functional programmer :P