diff options
Diffstat (limited to 'rpn.hs')
-rwxr-xr-x | rpn.hs | 28 |
1 files changed, 18 insertions, 10 deletions
@@ -1,5 +1,7 @@ | |||
1 | #!/usr/bin/env runghc | 1 | #!/usr/bin/env runghc |
2 | 2 | ||
3 | {-# LANGUAGE ViewPatterns #-} | ||
4 | |||
3 | import Control.Monad (join, sequence, forever) | 5 | import Control.Monad (join, sequence, forever) |
4 | import Control.Applicative | 6 | import Control.Applicative |
5 | import System.Environment | 7 | import System.Environment |
@@ -10,7 +12,7 @@ import qualified Control.Monad.State as S | |||
10 | import qualified Data.Map as M | 12 | import qualified Data.Map as M |
11 | import System.IO | 13 | import System.IO |
12 | 14 | ||
13 | data Symbol a = Number a a | Err | Add | Sub | Mult | Div | Unc | Exp deriving (Eq, Ord, Show) | 15 | data Symbol a = Number a a | Err | Add | Sub | Mult | Div | Unc | Exp | Pow deriving (Eq, Ord, Show) |
14 | instance Floating a => Num (Symbol a) where | 16 | instance Floating a => Num (Symbol a) where |
15 | (Number x del) + (Number y del') = Number (x + y) (abs $ gMean [del, del']) | 17 | (Number x del) + (Number y del') = Number (x + y) (abs $ gMean [del, del']) |
16 | _ + _ = Err | 18 | _ + _ = Err |
@@ -42,7 +44,7 @@ fromSymbol _ = (0, 0) | |||
42 | 44 | ||
43 | 45 | ||
44 | pPrint :: (Show a, Fractional a) => Symbol a -> String | 46 | pPrint :: (Show a, Fractional a) => Symbol a -> String |
45 | pPrint (Number x d) = (show x) ++ " ± " ++ (show d) ++ " (relative error: " ++ (show $ d / x) ++ ")" | 47 | pPrint (Number x d) = x `seq` d `seq` (show x) ++ " ± " ++ (show d) ++ " (relative error: " ++ (show $ d / x) ++ ")" |
46 | pPrint s = show s | 48 | pPrint s = show s |
47 | 49 | ||
48 | main :: IO () | 50 | main :: IO () |
@@ -71,7 +73,7 @@ clarifySymbol s = maybe clarify' (return . words) =<< lookupEnv s | |||
71 | 73 | ||
72 | isKnownSymbol :: String -> Bool | 74 | isKnownSymbol :: String -> Bool |
73 | isKnownSymbol s = or [ | 75 | isKnownSymbol s = or [ |
74 | s `elem` ["+", "-", "*", "/", "±", "+-", "e"], | 76 | s `elem` ["+", "-", "*", "/", "±", "+-", "e", "^"], |
75 | isJust $ (maybeRead s :: Maybe Double) | 77 | isJust $ (maybeRead s :: Maybe Double) |
76 | ] | 78 | ] |
77 | 79 | ||
@@ -91,17 +93,18 @@ interpreteSymbol "/" = Div | |||
91 | interpreteSymbol "±" = Unc | 93 | interpreteSymbol "±" = Unc |
92 | interpreteSymbol "+-" = Unc | 94 | interpreteSymbol "+-" = Unc |
93 | interpreteSymbol "e" = Exp | 95 | interpreteSymbol "e" = Exp |
96 | interpreteSymbol "^" = Pow | ||
94 | interpreteSymbol x = Number (read x) 0 | 97 | interpreteSymbol x = Number (read x) 0 |
95 | 98 | ||
96 | evalExpVec :: Floating a => [Symbol a] -> Symbol a | 99 | evalExpVec :: (Floating a, RealFrac a, Eq a) => [Symbol a] -> Symbol a |
97 | evalExpVec is = head . snd $ S.runState (evalExpVec' is) [] | 100 | evalExpVec is = head . snd $ S.runState (evalExpVec' is) [] |
98 | 101 | ||
99 | evalExpVec' :: Floating a => [Symbol a] -> S.State [Symbol a] () | 102 | evalExpVec' :: (Floating a, RealFrac a, Eq a) => [Symbol a] -> S.State [Symbol a] () |
100 | evalExpVec' is = do | 103 | evalExpVec' is = do |
101 | sequence $ map evalExp is | 104 | sequence $ map evalExp is |
102 | return () | 105 | return () |
103 | 106 | ||
104 | evalExp :: Floating a => Symbol a -> S.State [Symbol a] () | 107 | evalExp :: (Floating a, RealFrac a, Eq a) => Symbol a -> S.State [Symbol a] () |
105 | evalExp (Number x del) = do | 108 | evalExp (Number x del) = do |
106 | state <- S.get | 109 | state <- S.get |
107 | S.put $ ((Number x del):state) | 110 | S.put $ ((Number x del):state) |
@@ -121,8 +124,13 @@ evalExp Div = do | |||
121 | state <- S.get | 124 | state <- S.get |
122 | S.put $ ((foldl1 (/) . reverse $ take 2 state):drop 2 state) | 125 | S.put $ ((foldl1 (/) . reverse $ take 2 state):drop 2 state) |
123 | evalExp Exp = do | 126 | evalExp Exp = do |
124 | state <- S.get | 127 | (e:b:state) <- S.get |
128 | S.put $ (b * (Number (10 ** (fst $ fromSymbol e)) 0)):state | ||
129 | evalExp Pow = do | ||
130 | ((Number b'@(round -> b) 0):(Number y dY):(Number a'@(round -> a) 0):(Number x dX):state) <- S.get | ||
125 | let | 131 | let |
126 | b = state !! 1 | 132 | prod = (x^^a) * (y^^b) |
127 | e = state !! 0 | 133 | dX' = dX / x |
128 | S.put $ ((b * (Number (10 ** (fst $ fromSymbol e)) 0)):drop 2 state) | 134 | dY' = dY / y |
135 | err = prod * (sqrt $ (a' * dX')^2 + (b' * dY')^2) | ||
136 | S.put $ (Number prod err):state | ||