
[snip]
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.