-
Notifications
You must be signed in to change notification settings - Fork 1
/
ParseMonad.hs
78 lines (54 loc) · 1.63 KB
/
ParseMonad.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
63
64
65
66
67
68
69
70
71
72
73
74
75
--Derived from Philip Walder's Parser Monad
module ParseMonad where --(Parser, apply, parse, char, spot, token, star, plus, parseInt) where
import Char
import Monad
-- a: parsed Object, String: unparsed substring
data Parser a = Parser (String -> [(a, String)])
--Apply a parser to a string
apply :: Parser a -> String -> [(a, String)]
apply (Parser f) s = f s
-- Return parsed object
parse :: Parser a -> String -> a
parse m s = head [x | (x,t) <- apply m s, t == ""]
instance Monad Parser where
return x = Parser (\s -> [(x,s)])
m >>= k = Parser (\s ->
[ (y,u) |
(x,t) <- apply m s,
(y,u) <- apply (k x) t])
instance MonadPlus Parser where
mzero = Parser (\s -> [])
mplus m n = Parser (\s -> apply m s ++ apply n s)
--Parser from a predicate
spot :: (Char -> Bool) -> Parser Char
spot p = Parser f
where
f [] = []
f (c:s) | p c = [(c,s)]
| otherwise = []
--spot p = do { c <- char; guard (p c); return c }
--parser for a particular character
token c = spot (==c)
--parse a single character
char :: Parser Char
char = Parser f
where
f [] = []
f (c:s) = [(c,s)]
--Kleene star: zero or more
star :: Parser a -> Parser [a]
star p = plus p `mplus` return []
--one or more
plus :: Parser a -> Parser [a]
plus p = do { x <- p; xs <- star p; return (x:xs) }
--Parsing a string
parseStr :: Parser String
parseStr = do { s <- plus (spot isAlpha); return s }
--Parsing an integer
--match a natural
parseNat :: Parser Int
parseNat = do { s <- plus (spot isDigit); return (read s) }
parseNeg :: Parser Int
parseNeg = do { token '-'; n <- parseNat; return (-n) }
parseInt :: Parser Int
parseInt = parseNat `mplus` parseNeg