In general this is not possible. parsec
does not expect a lot from its stream type, in particular there is no way to efficently split a stream.
But for a concrete stream type (e.g. String
, or [a]
, or ByteString
) a hack like this would work:
parseWithSource :: Parsec [c] u a -> Parsec [c] u ([c], a)
parseWithSource p = do
input <- getInput
a <- p
input' <- getInput
return (take (length input - length input') input, a)
This solution relies on function getInput
that returns current input. So we can get the input twice: before and after parsing, this gives us exact number of consumed elements, and knowing that we can take
these elements from the original input.
Here you can see it in action:
*Main Text.Parsec> parseTest (between (char 'x') (char 'x') (parseWithSource ((read :: String -> Int) `fmap` many1 digit))) "x1234x"
("1234",1234)
But you should also look into attoparsec
, as it properly supports this functionality with the match function.
Parser
monad that extract tokens one by one and return some data structures. – Mark Karpov