-- solutions for excercise 09 (Parsec) import Text.Parsec import Text.Parsec.String import Control.Applicative ((<$>), (<*>), (<$), (<*), (*>), liftA2, liftA3) import Data.Functor (fmap) -- | Number parser, epic version :-} -- Parses positive number of digits then optionally a decimal part, -- consisting of a decimal point and a positive number of digits. -- There must not be any more character at the end. numbers1 :: Parser String numbers1 = flip (<*) eof $ liftA2 (++) (many1 digit) $ option "" $ liftA2 (:) (char '.') $ many1 digit -- | Number parser, readable version -- Same rules as numbers1 numbers2 :: Parser String numbers2 = do integerPart <- many1 digit fractionalPart <- ( do point <- char '.' digits <- many1 digit return (point : digits) ) <|> return "" eof return (integerPart ++ fractionalPart) -- | Expressions with parentheses, epic version :-} -- Requires end of input afterwards. parens1 :: Parser String parens1 = parens1' <* eof where parens1' = fmap concat $ many p p = addPars $ char '(' *> (parens1' <|> return "") <* char ')' addPars = fmap (\xs -> "(" ++ xs ++ ")") -- | Expressions with parentheses, readable version -- Requires end of input afterwards. parens2 :: Parser String parens2 = do parens <- parens2' eof return parens where parens2' = ( do exp <- do open <- char '(' exp <- parens2' close <- char ')' return $ open:exp++[close] rest <- parens2' return $ exp ++ rest ) <|> return "" -- | Date type for parsing data Date = Date { year :: Int , month :: Int , day :: Int } deriving Show -- | Date parser, applicative version -- Requires eof at the end of input. date1 :: Parser Date date1 = liftA3 Date (read <$> count 4 digit <* char '-') (read <$> count 2 digit <* char '-') (read <$> count 2 digit <* eof) -- | Date parser, applicative version -- Requires eof at the end of input. date2 :: Parser Date date2 = do y <- count 4 digit char '-' m <- count 2 digit char '-' d <- count 2 digit eof return $ Date (read y) (read m) (read d) -- Sorry, but the (infix) expression parser is rather compilcated to code. -- I meant to use the prefix one :-/. -- For infix expression parsers, see for example Text.Parsec.Expr