0

I've defined the following custom parser:

newtype St = St Int
type TxsParser = ParsecT String St (State St)

Now to be able to run this parser, I have to use the runParserT function.

runParserT :: Stream s m t 
           => ParsecT s u m a 
           -> u 
           -> SourceName
           -> s 
           -> m (Either ParseError a) 

Which instantiated to my custom parser reads:

runParserT :: ParsecT String St (State St) a 
           -> St 
           -> SourceName 
           -> String 
           -> State St (Either ParseError a)

But this means that if I want to evaluate the result of runParserT (which is a state monad) I have to supply another initial state (of type St in this case). For instance:

 evalState (runParserT myParser (St 0) fp input) (St 0)

While this works, it seems wrong that I have to repeat the state twice. Does this mean that mixing ParsecT and the State monads is not a good idea?

Damian Nadales
  • 4,907
  • 1
  • 21
  • 34
  • It's not a bad idea, it just may not be *necessary*. The two states are logically separate; one initializes the parser itself, the other initializes the `State` *produced* by the parser. – chepner Mar 15 '18 at 15:06

2 Answers2

6

Correct: mixing ParsecT and StateT is not a good idea. The ParsecT monad carefully restores its state when it backtracks, an action that an enclosing (or enclosed) StateT transformer doesn't and can't know about or handle correctly.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
6

ParsecT provides state. State provides state. Using both together gives you two independent states.

You have to initialize both, which is why you see it twice.

There's nothing wrong with using them together if you want two separate sources of state (e.g. one that backtracks and one that doesn't), but if you only wanted one, this is clearly not what you'd do.

that other guy
  • 116,971
  • 11
  • 170
  • 194