summaryrefslogtreecommitdiff
path: root/rpn.hs
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@praseodym.org>2015-03-05 18:01:15 +0000
committerGregor Kleen <gkleen@praseodym.org>2015-03-05 18:01:15 +0000
commit7aa86b0a785cb428a7b54c606fd854ba87789503 (patch)
tree28843a0ed954e0de064cda95e822adc78f12eebe /rpn.hs
downloadgausshs-7aa86b0a785cb428a7b54c606fd854ba87789503.tar
gausshs-7aa86b0a785cb428a7b54c606fd854ba87789503.tar.gz
gausshs-7aa86b0a785cb428a7b54c606fd854ba87789503.tar.bz2
gausshs-7aa86b0a785cb428a7b54c606fd854ba87789503.tar.xz
gausshs-7aa86b0a785cb428a7b54c606fd854ba87789503.zip
Initial commit
Diffstat (limited to 'rpn.hs')
-rw-r--r--rpn.hs78
1 files changed, 78 insertions, 0 deletions
diff --git a/rpn.hs b/rpn.hs
new file mode 100644
index 0000000..a0d33ef
--- /dev/null
+++ b/rpn.hs
@@ -0,0 +1,78 @@
1import Control.Monad (join, sequence)
2import System.Environment (getArgs)
3import qualified Control.Monad.State as S
4
5data Symbol a = Number a a | Err | Add | Sub | Mult | Div | Unc deriving (Eq, Ord, Show)
6instance Floating a => Num (Symbol a) where
7 (Number x del) + (Number y del') = Number (x + y) (abs $ gMean [del, del'])
8 _ + _ = Err
9 (Number x del) * (Number y del') = Number (x * y) (abs $ (x * y) * (gMean [del / x, del' / y]))
10 _ * _ = Err
11 negate (Number x del) = Number (negate x) del
12 negate _ = Err
13 abs (Number x del) = Number (abs x) del
14 abs _ = Err
15 signum (Number x del) = Number (signum x) 0
16 signum _ = Err
17 fromInteger i = Number (fromInteger i) 0
18
19instance Floating a => Fractional (Symbol a) where
20 recip (Number x del) = Number (recip x) (abs $ (recip x) * (del / x))
21 recip _ = Err
22 fromRational x = Number (fromRational x) 0
23
24dropUnc :: Floating a => Symbol a -> a
25dropUnc (Number x _) = x
26dropUnc _ = 0
27
28gMean :: Floating a => [a] -> a
29gMean xs = sqrt $ foldl1 (+) $ map (\x -> x * x) xs
30
31fromSymbol :: Floating a => Symbol a -> (a, a)
32fromSymbol (Number x d) = (x, d)
33fromSymbol _ = (0, 0)
34
35main :: IO ()
36main = do
37 (mode:stdin:_) <- getArgs
38 let symbols = map interpreteSymbol $ join $ map words . lines $ stdin
39 result = evalExpVec symbols
40 case mode of
41 "n" -> putStrLn . show . fst $ fromSymbol result
42 "e" -> putStrLn . show . snd $ fromSymbol result
43
44interpreteSymbol :: String -> Symbol Double
45interpreteSymbol "+" = Add
46interpreteSymbol "-" = Sub
47interpreteSymbol "*" = Mult
48interpreteSymbol "/" = Div
49interpreteSymbol "±" = Unc
50interpreteSymbol x = Number (read x) 0
51
52evalExpVec :: Floating a => [Symbol a] -> Symbol a
53evalExpVec is = head . snd $ S.runState (evalExpVec' is) []
54
55evalExpVec' :: Floating a => [Symbol a] -> S.State [Symbol a] ()
56evalExpVec' is = do
57 sequence $ map evalExp is
58 return ()
59
60evalExp :: Floating a => Symbol a -> S.State [Symbol a] ()
61evalExp (Number x del) = do
62 state <- S.get
63 S.put $ ((Number x del):state)
64evalExp Unc = do
65 state <- S.get
66 S.put $ ((Number (dropUnc (state !! 1)) (dropUnc (state !! 0))):drop 2 state)
67evalExp Add = do
68 state <- S.get
69 S.put $ ((foldl1 (+) $ take 2 state):drop 2 state)
70evalExp Sub = do
71 state <- S.get
72 S.put $ ((foldl1 (-) . reverse $ take 2 state):drop 2 state)
73evalExp Mult = do
74 state <- S.get
75 S.put $ ((foldl1 (*) $ take 2 state):drop 2 state)
76evalExp Div = do
77 state <- S.get
78 S.put $ ((foldl1 (/) . reverse $ take 2 state):drop 2 state)