{-# LANGUAGE OverloadedStrings #-} module Main where import System.Environment import System.IO import Control.Applicative import Data.Maybe import Data.Attoparsec.Text as A import Data.Ratio import Data.List as L import Data.Vector ((!?)) import qualified Data.Text as T import qualified Data.Text.IO as T import qualified Data.Vector as V data Expr a = Num !a | Var !Int | Fun !(a -> a) !(Expr a) | Comb !(a -> a -> a) !(Expr a) !(Expr a) main :: IO () main = do (tExpr:vars) <- getArgs let Right rExpr = parseOnly expr (T.pack tExpr) let Just res = eval rExpr $ V.fromList $ map (pNum . T.pack) vars output res pNum :: T.Text -> Rational pNum t = res where Right res = parseOnly (rational <* endOfInput) t output :: Rational -> IO () output = putStrLn . display 10 display :: (Integral i, Show i) => Int -> Ratio i -> String display len rat = (if num < 0 then "-" else "") ++ show ip ++ "." ++ L.take len (go (abs num - ip * den)) where num = numerator rat den = denominator rat ip = abs num `quot` den go 0 = "" go x = shows d (go next) where (d, next) = (10 * x) `quotRem` den eval :: (Fractional a) => Expr a -> V.Vector a -> Maybe a eval (Num d) _ = Just d eval (Var i) v = v !? i eval (Fun f x) v = f <$> eval x v eval (Comb f x y) v = f <$> eval x v <*> eval y v expr :: (Fractional a) => Parser (Expr a) expr = skipSpace *> rExpr <* skipSpace term :: (Fractional a) => Parser (Expr a) term = skipSpace *> rTerm <* skipSpace rExpr :: (Fractional a) => Parser (Expr a) rExpr = Comb (+) <$> term <* "+" <*> expr <|> Comb (-) <$> term <* "-" <*> expr <|> term rTerm :: (Fractional a) => Parser (Expr a) rTerm = Comb (*) <$> num <* "*" <*> term <|> Comb (/) <$> num <* "/" <*> term <|> Fun negate <$> ("-" *> term) <|> num num :: (Fractional a) => Parser (Expr a) num = Num <$> (skipSpace *> rational <* skipSpace) <|> skipSpace *> "(" *> expr <* ")" <* skipSpace <|> Var <$> (skipSpace *> "[" *> decimal <* "]" <* skipSpace)