Reputation: 2312
I want to thread some state through a parser but I don't want to have a single type for state for all parts of the parser, because some types just don't make sense in some parts of the parser, but are needed in others. I could make a bigger more complicated state type with either optional values or a discriminated union, but I think that is ugly.
So I want to be able to map a function to the state of the parser.
Concretely, I want a function with the following signature
stateMap: (f:'a->'b) (p:Parser<'x,'a>) -> Parser<'x,'b>
Does such a function or operator exist in FParsec? If not, what is the idiomatic way to create it?
Upvotes: 2
Views: 226
Reputation: 11577
From checking the source code my impression is that there's no such method today and it's not that easy to implement. Parser<_>
is defined liked this:
type Parser<'Result, 'UserState> = CharStream<'UserState> -> Reply<'Result>
If there's a way to map CharStream<'a>
to CharStream<'b>
then we would reach the goal.
However investigating the source for CharStream<_>
reveals some problems:
map
for CharStream<_>
.CharStream<_>
is IDisposable
which implies FParsec
creates one instance of the CharStream<_>
at the start of parsing and this is assumed to trace through the whole parsing process. Creating a new CharStream<_>
based on an existing one and use that instead don't seem to match the design.CharStream<_>
inherits CharStream
- So CharStream
seems to do must heavy lifting when it comes to paging and CharStream<_>
is just there to pair the stream with the user state. If CharStream<_>
used a composition over inheritance we could create a new CharStream<_>
that still used the already existing CharStream
but with inheritance that's not possible. My guess is that inheritance is chosen here to avoid an extra deref and thus save a few clockcycles (performance is important for parsers).So I think the idea of composite user states sounds interesting but from what I can tell this is not supported by FParsec right now.
Upvotes: 1