I've defined a parser using Parsec, which has type Parsec Text () a for some a. I've also got a "deal with this chunk" function, which writes the thing I've parsed to a file and has type a -> IO (). The file format that it's parsing means that we get back to "top level" reasonably frequently.
Is there a way to take my original parser and "lift it" into the IO monad? I'm imagining something with the following type signature:
liftParser :: Parsec Text () a -> (a -> IO ()) -> ParsecT Text () IO ()
where the first argument is the pure parser and the second is the "do something with the thing I parsed" function.
Obviously, I can bodge together what I need by redefining my original parser in IO too, but that means my unit tests look horrible, and it just feels like the wrong approach.
Also, I can't do something crazy like calling runParserT because that would drop the source position information - if there's an error on line 1000 of the input, I'd like the error message to say so.
So is there a way to do this and, if so, how? Also, is this a sensible thing to do? I imagine that I'm at least managing to avoid accumulating the output data. And, assuming that I manage something like this, should I expect Parsec to manage to discard the input data that it's already dealt with?
ParsecT Text () m, leavingmundecided. Then your pure tests can test it onIdentity, but you can instantiate atIOwhen you need to. - luquirunParserTfor whichever reason, you can simply usesetPositionto set Parsec's idea of the current source location (without skipping in the stream). - that other guy