[Haskell-beginners] Parsec and Validation
Stephen Tetley
stephen.tetley at gmail.com
Sat Jul 31 17:47:31 EDT 2010
Hello Vladimir
In general it is better to avoid the try combinator and left factor
the grammar instead.
Because parsers are functions you can abuse left factoring a bit,
parse the prefix in a top level combinator and supply the prefix to
the sub-parsers:
leftFactoredTime :: Parser TimeOfDay
leftFactoredTime = do
hh <- width2Num
sep <- optionMaybe (oneOf ";,.")
case sep of
Nothing -> tTimeHourMin hh
Just _ -> t24hrClock hh
tTimeHourMin :: Int -> Parser TimeOfDay
tTimeHourMin hh = do
mm <- width2Num
return (TimeOfDay hh mm 0)
t24hrClock :: Int -> Parser TimeOfDay
t24hrClock hh = do
mm <- width2Num
return (TimeOfDay hh mm 0)
However in this case, the 24 hour clock and TimeHourMin are identical
functions, the separator is a McGuffin [*] so:
betterTime :: Parser TimeOfDay
betterTime = do
hh <- rangeP 0 23 width2Num
_sep <- optionMaybe (oneOf ";,.")
mm <- rangeP 0 59 width2Num
return (TimeOfDay hh mm 0)
To parse ranges I would make a new combinator that takes a range plus
a number parser and returns a new number parser:
rangeP :: Int -> Int -> Parser Int -> Parser Int
rangeP hi lo p = do
a <- p
if (lo <= a && a <= hi) then return a else fail "out-of-range"
Finally avoiding using read is good when using Parsec. Parsec has
token parsers to read numbers, but here read can be avoided with this
one:
width2Num :: Parser Int
width2Num = do
a <- digit
b <- digit
return $ (10*digitToInt a) + digitToInt b
digitToInt is in the Data.Char module.
[*] A plot device used by Alfred Hitchcock films to throw the viewer
off the scent.
More information about the Beginners
mailing list