Parsec - Roman Numerals - doesn't parse when I change the order, even with try

75 views Asked by At

I'm writing a roman number parser for the daily programmer redit challenge. I've written a parsec parser to implement the challenge part of the challenge. This is to support brackets that multiply their contents by 1000.

(II)II = 2002

Now I've got the parser working however something isn't quite clear about using try.

This works:

romAdv :: GenParser Char st RomAdv
romAdv = complex <|> simple

But this does not:

romAdv :: GenParser Char st RomAdv
romAdv = try simple <|> complex

Can anyone please explain? I thought they would be somewhat equivalent.

Code:

data Numeral = I | V | X | L | C | D | M deriving (Read, Show)
type RomNum = [Numeral] deriving (Read, Show)
data RomAdv = Bracketed RomAdv RomNum | Simple RomNum deriving (Read, Show)

romNumbers :: GenParser Char st [RomAdv]
romNumbers = do
  numbers <- sepBy (romAdv) (char '\n')
  eof
  return numbers

romAdv :: GenParser Char st RomAdv
romAdv = complex <|> simple

complex :: GenParser Char st RomAdv
complex =
  do multed <- between (char '(') (char ')') romAdv
     remainder <- romNum
     return (Bracketed multed remainder)

simple :: GenParser Char st RomAdv
simple = do
  number <- romNum
  return (Simple number)

romNum :: GenParser Char st [Numeral]
romNum = many numeral

numeral :: GenParser Char st Numeral
numeral = do
  c <- char 'I' <|> char 'V' <|> char 'X' <|> char 'L' <|> char 'C' <|> char 'D' <|> char 'M'
  return $ read [c]
1

There are 1 answers

0
poida On BEST ANSWER

Figured it out.

As it is my grammar would parse "" as (Simple []). Changing the grammar so that Simple requires at least one roman numeral gave me the desired behavior. try was working fine after all, behaving as I thought it would, I just didn't recognise it.

data Numeral = I | V | X | L | C | D | M deriving (Read, Show)
type RomNum = [Numeral]
data RomAdv = Bracketed RomAdv RomNum | Simple Numeral RomNum deriving (Show)

romAdv :: GenParser Char st RomAdv
romAdv = try simple <|> complex

simple :: GenParser Char st RomAdv
simple = do
  number1 <- numeral
  number <- romNum
  return (Simple number1 number)