You can enhance Parser monad with StateT monad transformer to get what you want. This works well with the rest of the library, as most combinators use type classes rather than specific types (this means that you donβt have to do much for the code to work). Here is a worthy example of this. It parses a grammar with identifiers and characters separated by spaces. Each identifier is assigned a unique number.
module Main where import Text.Trifecta import Control.Monad.State import Control.Applicative import Data.Monoid data Identifier = Identifier String Int deriving (Show) identifier :: StateT Int Parser Identifier identifier = do name <- some letter newId <- get modify (+1) return $ Identifier name newId symbolToken :: Parser Char symbolToken = oneOf "+-*/" data Token = IdentifierToken Identifier | SymbolToken Char deriving (Show) singleToken :: StateT Int Parser Token singleToken = try (IdentifierToken <$> identifier) <|> (SymbolToken <$> lift symbolToken) parseTokens :: StateT Int Parser [Token] parseTokens = singleToken `sepBy1` spaces testParse :: String -> Result [Token] testParse = parseString (evalStateT parseTokens 0) mempty test1 :: Result [Token] test1 = testParse "these are identifiers and + some / symbols -"
test1 results in:
Success [IdentifierToken (Identifier "these" 0) ,IdentifierToken (Identifier "are" 1) ,IdentifierToken (Identifier "identifiers" 2) ,IdentifierToken (Identifier "and" 3) ,SymbolToken '+',IdentifierToken (Identifier "some" 4) ,SymbolToken '/',IdentifierToken (Identifier "symbols" 5),SymbolToken '-']
source share