1

A noob Haskell question.

I have had fun writing a few parsers with both Parsec and AttoParsec. I now want to gather information during the parsing process (basically build a symbol table) and using the WriterT monad transformer seems like a good option.

I have this working now in this simple example:

module NewParse where

import qualified Text.ParserCombinators.Parsec as A
import Control.Monad.Trans (lift)
import Control.Monad.Writer (WriterT, tell,  runWriterT)
type WParser a = WriterT [String] A.Parser a 

data StoryToken = StoryToken Char deriving (Show)

getToken :: WParser StoryToken
getToken = do
  tell ["hello from Writer T"]
  c <- lift A.anyChar 
  return $ StoryToken c 

test = A.parse (runWriterT getToken) "story" "#"

It works great. Calling test in ghci gives me this:

*NewParse> test
Right (StoryToken '#',["hello"])

What I'm kind of dreading when applying this to my parser code having to lift the parser monad for every every call it. I'll be calling tell relatively infrequently but parser functions a lot. The code is going to get a lot uglier.

Is there a way of easily exposing certain functions from Parsec so I don't have to use lift in the code?

A solution that worked for me was creating my own function

anyChar = lift A.anyChar

Which is cool but would require creating similar shadow functions for every function I use from parsec.

And I don't mind doing that but just wondered if there was a better, less boiler-platey way of achieving the same thing.

Any help gratefully received :)

4

1 回答 1

2

Parsec allows for users to carry state through parsers just use

addSym :: String -> Parsec String [String] ()
addSym = void . updateState . (:) -- append a string to the symbol list

type MyParser = Parsec String [String]

This will handle backtracking correctly.

于 2013-10-22T17:24:13.593 回答