-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathStackComputer.hs
62 lines (48 loc) · 1.7 KB
/
StackComputer.hs
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
-- Give an integer greater than or equality to 0. and an add operator,
-- and a stack computer just have two instruction -- push and add,
-- computer the expression like 1+2+3.
module StackComputer
(
sumExpr
) where
import Control.Monad
sumExpr :: String -> Maybe Int
sumExpr = fmap execute . fmap readLexTree . readExpr
execute :: [StackComputer] -> Int
execute = head . execute' []
execute' :: [Int] -> [StackComputer] -> [Int]
execute' xs [] = xs
execute' (y:x:xs) (Add:zs) = execute' ((x+y): xs) zs
execute' xs (Push n:zs) = execute' (n: xs) zs
readLexTree :: LexTree -> [StackComputer]
readLexTree (LexInt n) = [Push n]
readLexTree ((left, right) :-> _) = readLexTree left <> readLexTree right <> [Add]
readExpr :: String -> Maybe LexTree
readExpr s = join $ do
(x, s') <- readLexInt s
return $ readExpr' x s'
readExpr' :: LexTree -> String -> Maybe LexTree
readExpr' x "" = return x
readExpr' x s = join $ do
(_, s') <- readAdd s
(y, s'') <- readLexInt s'
let a = (x, y) :-> LexAdd
return $ readExpr' a s''
readAdd :: String -> Maybe ((), String)
readAdd ('+':xs) = return ((), xs)
readAdd _ = mzero
readLexInt :: String -> Maybe (LexTree, String)
readLexInt (x:xs)
| x `elem` ['0' .. '9'] = readLexInt' [x] xs
| otherwise = mzero
readLexInt _ = mzero
readLexInt' :: String -> String -> Maybe (LexTree, String)
readLexInt' xs a@(y:ys)
| y `elem` ['0' .. '9'] = readLexInt' (y:xs) ys
| otherwise = return (LexInt . read $ reverse xs, a)
readLexInt' xs "" = return (LexInt . read $ reverse xs, "")
data LexTree = LexInt Int
| (LexTree, LexTree) :-> LexAdd deriving (Show)
data LexAdd = LexAdd deriving (Show)
data StackComputer = Push Int
| Add deriving (Show)