Parsec: backtracking not working

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 '`')
   -- more complicated code here later
   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. - ?

+3
3

, , , F # ( ), . , , . , , .

, :

identP = many1 (digit <|> letter <|> char '.' <|> char '`')

typeP = try arrowP <|> identP

arrowP = do
  i <- identP
  string "->"
  t <- typeP
  return $ "(" ++ i ++ " -> " ++ t ++ ")"

run = flip parse "F# type syntax" $ do
        t <- typeP
        eof
        return t

:

Haskell> run "int"
Right "int"
Haskell> run "int->int"
Right "(int -> int)"
Haskell> run "int->int->int->int"
Right "(int -> (int -> (int -> int)))"

, , , type → type, , . , . , , . .

typeP = try arrowP <|> parens typeP <|> identP

arrowP = do
 i <- parens typeP <|> identP
 string "->"
 t <- typeP
 return $ "(" ++ i ++ " -> " ++ t ++ ")"

parens p  = between (char '(') (char ')') p

:

Haskell> run "int->int->int"
Right "(int -> (int -> int))"
Haskell> run "(int->int)->int"
Right "((int -> int) -> int)"
+5

, .

type ::= identifier | type -> type 
identifier ::= [A-Za-z0-9.`]+ 

-

typeStart ::= identifier 
type ::= typeStart (-> type)?
identifier ::= [A-Za-z0-9.`]+ 

, . ( , try , , , , , , , , - " try" .)

, Monadic Parser Combinators F # ( 7 #). , parsec docs ( , , ), , .

+4

, , sepBy1 , ->. , .

0

Source: https://habr.com/ru/post/1735985/


All Articles