module Algebra.Ring.Polynomial.Parser where import Algebra.Ring.Polynomial.Monomorphic import Control.Applicative hiding (many) import Control.Arrow import Data.Char import Data.Maybe import Data.Ratio import Text.Parsec hiding (optional, (<|>)) import Text.Parsec.String variable :: Parser Variable variable = Variable <$> letter <*> optional (char '_' *> index) variableWithPower :: Parser (Variable, Integer) variableWithPower = (,) <$> lexeme variable <*> option 1 power where power = symbol '^' *> parseInt index :: Parser Int index = digitToInt <$> digit <|> read <$ symbol '{' <*> lexeme (many1 digit) <* symbol '}' monomial :: Parser [(Variable, Integer)] monomial = many variableWithPower term :: Parser (Rational, [(Variable, Integer)]) term = signed' $ try $ (,) <$> option 1 coefficient <*> monomial <|> (,) <$> number <*> pure [] signed' p = do s <- optional sign (c, n) <- p return (fromMaybe 1 s * c, n) where sign = lexeme $ char '-' *> return (negate 1) <|> char '+' *> return 1 symbol :: Char -> Parser Char symbol = lexeme . char lexeme :: Parser a -> Parser a lexeme p = p <* spaces polyOp :: Parser (Polyn -> Polyn -> Polyn) polyOp = minusPolyn <$ symbol '-' <|> (++) <$ symbol '+' where minusPolyn xs ys = xs ++ map (first negate) ys expression :: Parser [(Rational, [(Variable, Integer)])] expression = spaces *> count 1 term `chainl1` polyOp <* eof coefficient :: Parser Rational coefficient = char '(' *> number <* char ')' <|> number number :: Parser Rational number = signed $ try (toRational <$> parseDouble) <|> try (lexeme $ (%) <$> parseInt <* symbol '/' <*> parseInt) <|> toRational <$> parseInt parseInt :: Parser Integer parseInt = lexeme $ read <$> many1 digit signed :: Num b => Parser b -> Parser b signed p = do s <- optional sign n <- p return $ fromMaybe 1 s * n where sign = lexeme $ char '-' *> return (negate 1) <|> char '+' *> return 1 parseDouble :: Parser Double parseDouble = lexeme $ do int <- many1 digit _ <- char '.' float <- many1 digit return $ read $ int ++ '.':float parsePolyn :: String -> Either ParseError Polyn parsePolyn = parse expression "polynomial"