Because the ParsecT s () (State st) a parser behaves differently than the Parsec s st Identity a parser when it comes to backtracking:
- The user state is reset when parsec tries to use the alternative after a failure that does not use input.
- But the base Monad
m does not back down; all effects that occurred on the way to the final analysis result are saved.
Consider the following example:
{-# LANGUAGE FlexibleContexts #-} module Foo where import Control.Applicative import Control.Monad.State import Text.Parsec.Prim hiding ((<|>), State(..)) import Text.Parsec.Error (ParseError) tick :: MonadState Int m => ParsecT s Int m () tick = do lift $ modify (+1) modifyState (+1) tickTock :: MonadState Int m => ParsecT s Int m () tickTock = (tick >> empty) <|> tick -- | run a parser that has both user state and an underlying state monad. -- -- Example: -- >>> run tickTock -- (Right 1,2) run :: ParsecT String Int (State Int) () -> (Either ParseError Int, Int) run m = runState (runParserT (m >> getState) initUserState "-" "") initStateState where initUserState = 0 initStateState = 0
As you can see, the main state monad registered two ticks (from both alternatives that were tested) while the user state of the Parsec monastic transformer only kept successful.
Lambdageek
source share