Easy way to change Parsec user state type?

I am looking for an easy way to combine two pieces of ParsecT code that have the same thread and monad but different user state and result. Essentially, such a function would be nice:

withUserState :: u -> ParsecT suma -> ParsecT svma 

The fact is that the user state is really useful in some cases, but I need different states at different times and do not want the state types to be larger. Do I have to somehow change the state to achieve this, or is there already a function for it that I cannot find at the moment?

Edit:

I think the alternative would be something like

 changeUserState :: (u -> v) -> ParsecT suma -> ParsecT svma 
+6
source share
2 answers

Parsec does not allow you to do this right out of the box, but you can achieve this using the public Parsec API as follows:

 {-# LANGUAGE ScopedTypeVariables #-} import Text.Parsec changeState :: forall msuva . (Functor m, Monad m) => (u -> v) -> (v -> u) -> ParsecT suma -> ParsecT svma changeState forward backward = mkPT . transform . runParsecT where mapState :: forall uv . (u -> v) -> State su -> State sv mapState f st = st { stateUser = f (stateUser st) } mapReply :: forall uv . (u -> v) -> Reply sua -> Reply sva mapReply f (Ok a st err) = Ok a (mapState f st) err mapReply _ (Error e) = Error e fmap3 = fmap . fmap . fmap transform :: (State su -> m (Consumed (m (Reply sua)))) -> (State sv -> m (Consumed (m (Reply sva)))) transform p st = fmap3 (mapReply forward) (p (mapState backward st)) 

Please note: this requires a forward and backward conversion between u and v . The reason is that you first need to put your environment in a local state, start your internal parser, and then convert it back.

ScopedTypeVariables and local type signatures exist for clarity only - feel free to delete them if you want.

+8
source

You cannot do this because the >>= operator is of type

  ParsecT suma -> (a -> ParsecT sumb) -> ParsecT sumb 

and (<*>) like

  ParsecT sum (a -> b) -> ParsecT suma -> ParsecT sumb 

The variable s universally quantified, but must coincide with both terms. Without >>= or <*> you cannot use applicative or monadic functions. This means that you would have absolutely no way to combine parsers with different states. The best way to do this is simply

 data PotentialStates = State1 ... | State2 ... | State3 ... 

and then just work with them.

+2
source

Source: https://habr.com/ru/post/950711/


All Articles