-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path4.hs
More file actions
134 lines (112 loc) · 4.2 KB
/
Copy path4.hs
File metadata and controls
134 lines (112 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import Control.Monad.Reader
import Data.Function
import Test.QuickCheck
import Control.Monad.State
newtype Expr = Expr String
deriving (Show, Eq)
instance Arbitrary Expr where
arbitrary = sized expr'
where expr' 0 = liftM Expr (oneof [return [x] | x <- ['a'..'z']])
expr' n | n > 0 = oneof operators
where subtree = expr' (n `div` 2)
oper s = do
Expr x <- subtree
Expr y <- subtree
return . Expr $ x ++ s:[] ++ y
operators = map oper "+-/*^"
shrink x = [x]
prop :: Expr -> Bool
prop (Expr x) = toRPN x == toRPN' x
prop' (Expr x) = toRPN'' x == toRPN' x
pqInsert dx opx [] = [opx,dx]
pqInsert dx opx [x] | not $ isOp x = [opx,dx,x]
| undefined = error "error 2"
pqInsert dx opx (opy:ys) | ((<=) `on` precedence) opx opy = opx:dx:opy:ys
| otherwise = opy:pqInsert dx opx ys
toRPN [] = []
toRPN [x] = [x]
toRPN (x:x':x'':xs) = reverse . loop xs $ pqInsert x'' x' [x]
where loop [] = id
loop (y:y':ys) = loop ys . pqInsert y' y
isOp :: Char -> Bool
isOp = (`elem` "+-/*^")
precedence :: (Num t) => Char -> t
precedence '^' = 5
precedence '/' = 4
precedence '*' = 3
precedence '-' = 2
precedence '+' = 1
precedence _ = 10
toRPN' = rpn [] []
where rpn accum stack [] = reverse accum ++ stack
rpn accum stack ('(':xs) = rpn accum ('(':stack) xs
rpn accum stack (')':is) = multiPop $ break (== '(') stack
where multiPop (xs,_:ys) = rpn (reverse xs ++ accum) ys is
multiPop (xs,[]) = rpn (reverse xs ++ accum) [] is
rpn accum stack input@(x:xs)
| not $ isOp x = rpn (x:accum) stack xs
| otherwise =
case stack of
[] -> rpn accum [x] xs
'(':_ -> pushX
op:ops -> if ((>=) `on` precedence) op x
then rpn (op:accum) ops input
else pushX
where pushX = rpn accum (x:stack) xs
type Stack a = [a]
type RPNState = (Stack Char, String)
accum :: State RPNState String
accum = do
(_,accum) <- get
return accum
stack :: State RPNState (Stack Char)
stack = fst `fmap` get
push x = do
(s,accum) <- get
put (x:s, accum)
return ()
modifyAccum f = do
(s,accum) <- get
put (s, f accum)
return ()
modifyStack f = do
(s,accum) <- get
put (f s, accum)
return ()
toRPN'' :: [Char] -> [Char]
toRPN'' input = fst $ runState (rpn input) ([], [])
where rpn [] = liftM2 (++) (reverse `liftM` accum) stack
rpn ('(':xs) = push '(' >> rpn xs
rpn (')':is) = do
s <- stack
let (xs, newStack) = break (== '(') s
modifyAccum (reverse xs ++)
case newStack of
(_:ys) -> modifyStack (const ys) >> rpn is
[] -> modifyStack (const []) >> rpn is
rpn input@(x:xs)
| not $ isOp x = modifyAccum (x:) >> rpn xs
| otherwise = do
s <- stack
case s of
[] -> push x >> rpn xs
'(':_ -> push x >> rpn xs
op:ops -> if ((>=) `on` precedence) op x
then do modifyAccum (op:)
modifyStack (const ops)
rpn input
else push x >> rpn xs
-- rpn accum stack input@(x:xs)
-- | not $ isOp x = rpn (x:accum) stack xs
-- | otherwise =
-- case stack of
-- [] -> rpn accum [x] xs
-- '(':_ -> pushX
-- op:ops -> if ((>=) `on` precedence) op x
-- then rpn (op:accum) ops input
-- else pushX
-- where pushX = rpn accum (x:stack) xs
main :: IO ()
main = do
x:xs <- liftM lines getContents
mapM_ (putStrLn . toRPN') xs