diff options
Diffstat (limited to 'rpn.hs')
-rw-r--r-- | rpn.hs | 53 |
1 files changed, 49 insertions, 4 deletions
@@ -1,8 +1,13 @@ | |||
1 | import Control.Monad (join, sequence) | 1 | import Control.Monad (join, sequence) |
2 | import System.Environment (getArgs) | 2 | import System.Environment (getArgs) |
3 | import Data.Maybe (listToMaybe, isJust) | ||
4 | import Data.Char (isSpace) | ||
5 | import Data.List (nub) | ||
3 | import qualified Control.Monad.State as S | 6 | import qualified Control.Monad.State as S |
7 | import qualified Data.Map as M | ||
8 | import System.IO | ||
4 | 9 | ||
5 | data Symbol a = Number a a | Err | Add | Sub | Mult | Div | Unc deriving (Eq, Ord, Show) | 10 | data Symbol a = Number a a | Err | Add | Sub | Mult | Div | Unc | Exp deriving (Eq, Ord, Show) |
6 | instance Floating a => Num (Symbol a) where | 11 | instance Floating a => Num (Symbol a) where |
7 | (Number x del) + (Number y del') = Number (x + y) (abs $ gMean [del, del']) | 12 | (Number x del) + (Number y del') = Number (x + y) (abs $ gMean [del, del']) |
8 | _ + _ = Err | 13 | _ + _ = Err |
@@ -32,14 +37,47 @@ fromSymbol :: Floating a => Symbol a -> (a, a) | |||
32 | fromSymbol (Number x d) = (x, d) | 37 | fromSymbol (Number x d) = (x, d) |
33 | fromSymbol _ = (0, 0) | 38 | fromSymbol _ = (0, 0) |
34 | 39 | ||
40 | |||
41 | pPrint :: Show a => Symbol a -> String | ||
42 | pPrint (Number x d) = (show x) ++ " ± " ++ (show d) | ||
43 | pPrint s = show s | ||
44 | |||
35 | main :: IO () | 45 | main :: IO () |
36 | main = do | 46 | main = do |
37 | (mode:stdin:_) <- getArgs | 47 | hSetBuffering stdin LineBuffering |
38 | let symbols = map interpreteSymbol $ join $ map words . lines $ stdin | 48 | hSetBuffering stdout NoBuffering |
39 | result = evalExpVec symbols | 49 | (mode:args) <- getArgs |
50 | let symbols = join . join $ map (map words) . map lines $ args | ||
51 | unknownSymbols = nub $ filter (not . isKnownSymbol) symbols | ||
52 | symbolMap <- sequence $ map (sequencePair . (\x -> (x, clarifySymbol x))) unknownSymbols | ||
53 | let symbolMap' = M.fromList symbolMap | ||
54 | symbols' = map (\x -> if x `elem` (M.keys symbolMap') then symbolMap' M.! x else [x]) symbols | ||
55 | symbols'' = map interpreteSymbol $ join symbols' | ||
56 | let result = evalExpVec symbols'' | ||
40 | case mode of | 57 | case mode of |
41 | "n" -> putStrLn . show . fst $ fromSymbol result | 58 | "n" -> putStrLn . show . fst $ fromSymbol result |
42 | "e" -> putStrLn . show . snd $ fromSymbol result | 59 | "e" -> putStrLn . show . snd $ fromSymbol result |
60 | _ -> putStrLn $ pPrint result | ||
61 | |||
62 | clarifySymbol :: String -> IO [String] | ||
63 | clarifySymbol s = do | ||
64 | putStr $ "Define " ++ s ++ ": " | ||
65 | line <- getLine | ||
66 | return $ words line | ||
67 | |||
68 | isKnownSymbol :: String -> Bool | ||
69 | isKnownSymbol s = or [ | ||
70 | s `elem` ["+", "-", "*", "/", "±", "e"], | ||
71 | isJust $ (maybeRead s :: Maybe Double) | ||
72 | ] | ||
73 | |||
74 | sequencePair :: (a, IO b) -> IO (a, b) | ||
75 | sequencePair (a, b) = do | ||
76 | b' <- b | ||
77 | return (a, b') | ||
78 | |||
79 | maybeRead :: (Read a) => String -> Maybe a | ||
80 | maybeRead = fmap fst . listToMaybe . filter (null . dropWhile isSpace . snd) . reads | ||
43 | 81 | ||
44 | interpreteSymbol :: String -> Symbol Double | 82 | interpreteSymbol :: String -> Symbol Double |
45 | interpreteSymbol "+" = Add | 83 | interpreteSymbol "+" = Add |
@@ -47,6 +85,7 @@ interpreteSymbol "-" = Sub | |||
47 | interpreteSymbol "*" = Mult | 85 | interpreteSymbol "*" = Mult |
48 | interpreteSymbol "/" = Div | 86 | interpreteSymbol "/" = Div |
49 | interpreteSymbol "±" = Unc | 87 | interpreteSymbol "±" = Unc |
88 | interpreteSymbol "e" = Exp | ||
50 | interpreteSymbol x = Number (read x) 0 | 89 | interpreteSymbol x = Number (read x) 0 |
51 | 90 | ||
52 | evalExpVec :: Floating a => [Symbol a] -> Symbol a | 91 | evalExpVec :: Floating a => [Symbol a] -> Symbol a |
@@ -76,3 +115,9 @@ evalExp Mult = do | |||
76 | evalExp Div = do | 115 | evalExp Div = do |
77 | state <- S.get | 116 | state <- S.get |
78 | S.put $ ((foldl1 (/) . reverse $ take 2 state):drop 2 state) | 117 | S.put $ ((foldl1 (/) . reverse $ take 2 state):drop 2 state) |
118 | evalExp Exp = do | ||
119 | state <- S.get | ||
120 | let | ||
121 | b = state !! 1 | ||
122 | e = state !! 0 | ||
123 | S.put $ ((b * (Number (10 ** (fst $ fromSymbol e)) 0)):drop 2 state) | ||