Search code examples
haskellparsec

How can I parse roman numerals in Haskell's Parsec?


I'm a Haskell beginner, and I'm trying to learn about Parsec by writing a parser that can consume either an arabic numeral, like "234," or a roman one, like "MCMLXIX." I found the library roman-numerals, and so I figured I'd try to use the fromRoman function somehow, in conjunction with Parsec, since I'll eventually need to get the arabic equivalent of the roman numeral. But I just don't quite yet know how to coerce the Maybe output of fromRoman into a Parser. This is what I have so far:

import Text.Parsec
import Text.Parsec.Text (Parser)
import Text.Numeral.Roman

arabicNum :: Parser Int
arabicNum = do
  n <- many1 digit
  return (read n)

isChapter :: Inline -> Bool
isChapter str = str == Str "CHAPTER"

number :: Parser Int
number = arabicNum <|> romanNum

romanNum :: Parser Int
romanNum = do
  str <- many1 char
  return case (fromRoman str) of
    Just n -> n
    Nothing -> Nothing

But, no dice, since I don't quite yet know what I'm doing.


Solution

  • If your Maybe is Nothing, you can fail to generate a parser error. If it's something, you can return it:

    romanNum :: Parser Int
    romanNum = do
      str <- many1 $ oneOf "MDCLXVI"
      case fromRoman str of
        Just n -> return n
        Nothing -> fail $ str ++ " is not a valid roman numeral"