I am trying to parse syntax like F #. I started writing the grammar of [F] Parsec and ran into problems, so I simplified the grammar down to this:
type ::= identifier | type -> type
identifier ::= [A-Za-z0-9.`]+
After I ran into problems with FParsec, I switched to Parsec since I have a full chapter of the book dedicated to explaining this . My code for this grammar
typeP = choice [identP, arrowP]
identP = do
id <- many1 (digit <|> letter <|> char '.' <|> char '`')
return id
arrowP = do
domain <- typeP
string "->"
range <- typeP
return $ "("++domain++" -> "++range++")"
run = parse (do t <- typeP
eof
return t) "F# type syntax"
The problem is that Parsec by default does not back off, so
> run "int"
Right "int"
-- works!
> run "int->int"
Left "F# type syntax"
unexpected "-"
expecting digit, letter, ".", "`" or end of input
-- doesn't work!
The first thing I tried was reordering typeP:
typeP = choice [arrowP, identP]
But this is just a stack overflow because the grammar is left-recursive - typeP never tries to try identP, because it keeps trying arrowPagain and again. Then I tried tryin different places, for example:
typeP = choice [try identP, arrowP]
, , (1) (2) "- > " .
, , , Parsec. - ?