I encoded the attoparsec parser and ended up in a template where I want to turn parsers into recursive parsers (recursively merging them with the monad bind β = operator).
So, I created a function to turn the parser into a recursive parser as follows:
recursiveParser :: (a -> A.Parser a) -> a -> A.Parser a recursiveParser parser a = (parser a >>= recursiveParser parser) <|> return a
This is useful if you have a recursive data type like
data Expression = ConsExpr Expression Expression | EmptyExpr parseRHS :: Expression -> Parser Expression parseRHS e = ConsExpr e <$> parseFoo parseExpression :: Parser Expression parseExpression = parseLHS >>= recursiveParser parseRHS where parseLHS = parseRHS EmptyExpr
Is there a more idiomatic solution? It seems that recursiveParser should be some kind of fold ... I also saw sepBy in the docs, but this method seems to work better for my application.
EDIT: Oh, actually now that I think about it, there really should be something like fix ... I donβt know how I forgot about it.
EDIT2: Rotsor is great for its alternative for my example, but I'm afraid that my AST is actually a bit more complicated. In fact, it looks something like this (although it is still simplified)
data Segment = Choice1 Expression | Choice2 Expression data Expression = ConsExpr Segment Expression | Token String | EmptyExpr
where the string a -> b brackets to the right and c:d brackets to the left, c : binding is more tight than -> .
those. a -> b evaluates to
(ConsExpr (Choice1 (Token "a")) (Token "b"))
and c:d evaluates to
(ConsExpr (Choice2 (Token "d")) (Token "c"))
I suppose I could use foldl for one and foldr for the other, but there is even more complexity. Note that it is recursive in a slightly strange way, so "a:b:c -> e:f -> :g:h ->" is actually a valid string, but "-> a" and "b:" - no. At the end of fix it seemed easier to me. I renamed the recursive method as follows:
fixParser :: (a -> A.Parser a) -> a -> A.Parser a fixParser parser a = (parser a >>= fixParser parser) <|> pure a
Thanks.