[Haskell-cafe] Newbie question about Parsec

david fries djf at gmx.ch
Mon Jan 18 13:09:23 EST 2010

Hey everybody

I've been playing around with Parsec a little bit lately. I like it a
lot, but now I've hit a bit of a challenge. Suppose I have to parse a
variable length string representing a time interval. Depending on how
many fields there are, the time is either interpreted as seconds,
minutes and seconds or hours, minutes and seconds. 

For example:

"... 31 ..." would be parsed as 31 seconds.
"... 05:31 ..." would be parsed as 5 minutes and 31 seconds.
"... 01:05:31 ..." would be parsed as 1 hour, 5 minutes and 31 seconds. 

I've come up with the following solution using optionMaybe to deal with
the problem:

data ElapsedTime = ElapsedTime {
     hours :: Int,
     minutes :: Int,
     seconds :: Int
} deriving (Show, Eq, Ord)

p_elapsed_time :: CharParser () ElapsedTime
p_elapsed_time = toElapsedTime <$> (optionMaybe p_Int) 
                               <*> (optionMaybe (char ':' *> p_Int))
                               <*> (optionMaybe (char ':' *> p_Int <*
    where toElapsedTime Nothing Nothing Nothing = ElapsedTime 0 0 0
          toElapsedTime (Just s) Nothing Nothing = ElapsedTime 0 0 s
          toElapsedTime (Just m) (Just s) Nothing = ElapsedTime 0 m s
          toElapsedTime (Just h) (Just m) (Just s) = ElapsedTime h m s

Where p_Int simply parses a sequence of digits as an Int and skipSpaces
does just that.

This works correctly, but it also feels kinda clumsy. For one the
compiler rightly complains about non-exhaustive pattern matches in the
definition of the toElapsedTime function, although I believe that's
negligible in that particular case. 
Is there a better i.e. more elegant way to tackle such a problem? 


More information about the Haskell-Cafe mailing list