17

I'm parsing an expression using Parsec and I want to keep track of variables in these expressions using the user state in Parsec. Unfortunately I don't really get how to do it.

Given the following code:

import Data.Set as Set
inp = "$x = $y + $z"

data Var = V String

var = do char '$'
      n <- many1 letter
      let v = Var n
       -- I want to modify the set of variables here
      return v

parseAssignment = ... -- parses the above assignment

run = case runIdentity $ runParserT parseAssignment Set.empty "" inp of
                   Left err -> ...
                   Right -> ...

So, the u in ParsecT s u m a would be Set.Set. But how would I integrate the state update into var?

I tried something like modify $ Set.insert v, but this doesn't work, since Set.Set is not a state monad.

bzn
  • 2,362
  • 1
  • 17
  • 20

2 Answers2

17

Unfortunately, Yuras' suggestion of updateParserState is not optimal (you'd use that function if you're looking to modify Parsec's internal state as well); instead you should pass a function that works over your custom user state (i.e. of type u -> u) to modifyState, such as in this example:

expr  = do
  x <- identifier
  modifyState (+1)
  -- ^ in this example, our type u is Int
  return (Id x)

or use any combination of the getState and putState functions. For your case, you'd do something like:

modifyState (Set.insert v)

See this link for more info.

For a more tutorial-like introduction to working with user state in Parsec, this document, though old, should be relevant.

Raeez
  • 2,423
  • 15
  • 12
  • Thanks! That's exactly what I need - could have looked at that function earlier... I somehow thought modifyState was related to modify from Control.Monad.State. – bzn Jun 25 '11 at 13:57
  • @bzn: It is related, though! If you think of Parsec as a state monad holding just the user state, they do the same thing. They differ only because `modifyState` ignores Parsec's internal state. – C. A. McCann Jun 25 '11 at 15:04
1

You can use updateParserState

Yuras
  • 13,856
  • 1
  • 45
  • 58