Skip to content

Alternative backtracks, but the transformer does not #64

@BartAdv

Description

@BartAdv

Steps to reproduce

import Control.Monad.State
import Lightyear
import Lightyear.Char
import Lightyear.Combinators
import Lightyear.Strings

-- hide the one from Lightyear.Strings
%hide Parser

Parser : Type -> Type
Parser = ParserT String (State Integer)

pModify : Parser ()
pModify = do
  token "+"
  modify (+ 1)

pTextBlock : Parser String
pTextBlock = pack <$> many anyChar

parser : Parser (List String)
parser = manyTill (choice alts) eof
  where
    alts : List (Parser String)
    alts = [ pure "" <* ((pModify <* string "can'thappen") <|> pModify)
           , pTextBlock
           ]

testParse : Parser a -> String -> Either String (a, Integer)
testParse p src =
  let initialVal = 0
      Id (r,s) = flip runStateT initialVal $ execParserT p (initialState Nothing src 8)
  in case r of
    MkReply _ (Success x)  => Right (x,s)
    MkReply _ (Failure es) => Left $ concat $ intersperse "\n" $ map display es

Running

λΠ> :exec testParse parser "+ho ho"

gives

Right (["", "ho ho"], 2)

Observed behaviour

The returned value means that our state had been modified two times. And this is because of the alternative:

((pModify <* string "can'thappen") <|> pModify)

which first enters the left branch (which won't succeed due to dummy string parse at the end), and then the right branch kicks in, and succeeds.

Expected behavior

If the default behavior is to backtrack, then the result of the transformer needs to be discarded as well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions