[Haskell-cafe] Parsec, state and/of my cluelessness

robert dockins robdockins at fastmail.fm
Mon Oct 17 14:53:27 EDT 2005


> Now comes the tricky part for me. Since the control can have three different
> types of children I use a helper that parses the body of the control using other
> parsers, collecting their results in three lists:
> ctrlBodyParser :: CharParser ([Value], [Property], [Control]) 
>                              ([Value], [Property], [Control])
> ctrlBodyParser =
>     do { c <- ctrlParser -- parse child control
>        ; (vs, ps, cs) <- getState
>        ; setState (vs, ps, (c : cs))
>        ; ctrlBodyParser
>        }
>     <|>

  [snip some alternatives]

>     <|>
>     do { getState } -- we're finished, return children

I think you might do better to make it tail-recursive (sort of) by 
passing intermediate lists as parameters to ctrlBodyParser rather than 
using state.  Parsec state (if I recall correctly) needs to have the 
same type throughout the parse, but here you really just want a bit of 
help accumulating some results in a section of the parse tree.  Try this:

ctrlBodyParser :: Parser ([Value],[Property],[Control])
ctrlBodyParser = ctrlBodyParser0 [] [] []

ctrlBodyParser0 :: [Value] -> [Property] -> [Control] ->
     Parser ([Value],[Property],[Control])
ctrlBodyParser0 vs ps cs =
     do { c <- ctrlParser; ctrlBodyBodyParser0 vs ps (c : cs) }
     .... etc
     do { return (vs,ps,cs) }

Be aware that your lists will come out in the reverse order that they 
apper in the text.

You can also use a single labeled record instead of the three list 
parameters and a tuple.

More information about the Haskell-Cafe mailing list