Skip to content

Instantly share code, notes, and snippets.

@jchia
Last active January 31, 2019 02:42
Show Gist options
  • Save jchia/89910ccc922c57e43026532ff9758116 to your computer and use it in GitHub Desktop.
Save jchia/89910ccc922c57e43026532ff9758116 to your computer and use it in GitHub Desktop.
Why is not a single input line processed? None of the traceM's got executed.
{-# LANGUAGE RecordWildCards, DuplicateRecordFields #-}
import ClassyPrelude hiding (try)
import Control.Monad.Except (MonadError, throwError)
import Control.Monad.State.Strict
import Control.Monad.Trans.Resource (ResourceT, runResourceT)
import Data.Conduit (ConduitM, runConduit, (.|))
import Data.Conduit.Combinators (sourceFile)
import qualified Data.Conduit.List as CL
import Data.Conduit.Lzma (decompress)
import qualified Data.Conduit.Text as CT
import Text.Megaparsec hiding (State)
import Text.Megaparsec.Char
data ParserState = ParserState { count1 :: Int, count2 :: Int } deriving Show
emptyState :: ParserState
emptyState = ParserState 0 0
type CharParser e s m = (MonadParsec e s m, Token s ~ Char, IsString (Tokens s))
-- Looks for "one" and increments count1.
oneParser :: (MonadState ParserState m, CharParser e s m) => m ()
oneParser = do
string "one"
traceM "one"
modify $ \ParserState{..} -> ParserState{count1 = count1 + 1, count2}
-- Looks for "two" and increments count2.
twoParser :: (MonadState ParserState m, CharParser e s m) => m ()
twoParser = do
string "two"
traceM "two"
modify $ \ParserState{..} -> ParserState{count2 = count2 + 1, count1}
-- Looks for "one" or "two" and increments count1 or count2 accordingly.
lineParser :: (MonadState ParserState m, CharParser e s m) => m ()
lineParser = do
traceM "lineParser"
try oneParser <|> twoParser
processEvents :: IO ParserState
processEvents = do
let stringifyLeftM :: MonadError IOException m => m (Either (ParseError Char ()) ()) -> m ()
stringifyLeftM x = x >>= \case
Left e -> throwError . userError . show $ e
Right () -> pure ()
processLine :: Text -> StateT ParserState (ResourceT IO) ()
processLine x = do
traceM $ "processLine " <> unpack x
stringifyLeftM . runParserT lineParser "" $ x
source = CL.sourceList ["one", "two", "one", "two", "two"]
conduit = source .| CL.mapM_ processLine
runResourceT . (`execStateT` emptyState) . runConduit $ conduit
main :: IO ()
main = do
parserState <- processEvents
print parserState
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment