I would like to know what can be considered as a best practice regarding the State
monad. I'm also open to any other suggestion.
I have a binary file to parse. It contains different header that need to be parsed in order to be able to read the complete file.
So the headers can be parsed using only State from the parse.
data ParseState = ParseState {
offset :: Int64
buffer :: B.ByteString
endianness :: Endianness
pointerSize :: MachineWord
positionStack :: [Int64]
}
This data is then used in a State
monad
type Parser a = State ParseState a
This can perfectly suite the parsing of the header. But as soon as I want to parse the complete file I need information from the header to be able to correctly read the file.
data Header = Header {
txtOffset :: Int64,
stringOffset :: Int64
}
I need the header information to continue parsing the file.
My idea was to use a new state monad that sit on top of the previous one. So I have a new StateT monad:
type ParserFullState a = StateT Header (State ParserState) a
Thus I can continue and build a whole set of parser function using the new state transformer.
I could also do it differently and add the header to the original ParseState
data.
The pros I can see at adding the header back into the ParserState
are the following:
- The return type of parser function is uniform
- No need to call
lift
to access the parser primitive.
The cons I can see are:
- There is no distinction between higher level parser and lower primitive.
- We can not tell clearly when the header is fully parse or when it is not. Thus making the parser modification more fragile.
What is your suggestion? Should I use the state transformer of should I add the header to the original state or anythings else?
Thanks.