-
Notifications
You must be signed in to change notification settings - Fork 1
/
parser.hs
119 lines (90 loc) · 2.55 KB
/
parser.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
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
module Parsec where
import Data.Char
import Data.Functor
import Control.Applicative
import Control.Monad
newtype Parser a = Parser {parse :: String -> [(a, String)]}
item :: Parser Char
item = Parser $ \s ->
case s of
[] -> []
(c:cs) -> [(c, cs)]
bind :: Parser a -> (a -> Parser b) -> Parser b
bind p f = Parser $ \s ->
concatMap (\(a, s') -> parse (f a) s') $ parse p s
unit :: a -> Parser a
unit a = Parser (\s -> [(a, s)])
instance Functor Parser where
fmap f p = Parser (\s ->
[(f a, s') | (a,s') <- parse p s])
instance Applicative Parser where
pure a = unit a
Parser cs1 <*> Parser cs2 = Parser (\s ->
[(f a, s2) | (f, s1) <- cs1 s, (a, s2) <- cs2 s1])
instance Monad Parser where
p >>= f = bind p f
return a = pure a
failure :: Parser a
failure = Parser (\cs -> [])
combine :: Parser a -> Parser a -> Parser a
combine p q = Parser (\s -> parse p s ++ parse q s)
-- class Monad m => MonadPlus m where
-- mzero :: m a
-- mplus :: m a -> m a -> m a
instance MonadPlus Parser where
mzero = failure
mplus = combine
option :: Parser a -> Parser a -> Parser a
option p q = Parser $ \s ->
case parse p s of
[] -> parse q s
res -> res
-- class Applicative f => Alternative f where
-- empty :: f a
-- (<|>) :: f a -> f a -> f a
-- | One or more.
-- some :: f a -> f [a]
-- some v = some_v
-- where
-- many_v = some_v <|> pure []
-- some_v = (:) <$> v <*> many_v
-- | Zero or more.
-- many :: f a -> f [a]
-- many v = many_v
-- where
-- many_v = some_v <|> pure []
-- some_v = (:) <$> v <*> many_v
-- instances of Alternative should satisfy the monoid laws
-- empty <|> x = x
-- x <|> empty = x
-- (x <|> y) <|> z = x <|> (y <|> z)
instance Alternative Parser where
empty = mzero
(<|>) = option
satisfy :: (Char -> Bool) -> Parser Char
satisfy pred = item `bind` \c ->
if pred c
then unit c
else (Parser (\cs -> []))
oneOf :: [Char] -> Parser Char
oneOf s = satisfy (flip elem s)
char :: Char -> Parser Char
char c = satisfy (c ==)
string :: String -> Parser String
string [] = return []
string (c:cs) = char c >> string cs >> return (c:cs)
natural :: Parser Integer
natural = read <$> some (satisfy isDigit)
spaces :: Parser String
spaces = many $ oneOf " \n\r"
digit :: Parser Char
digit = satisfy isDigit
token :: Parser a -> Parser a
token p = do { a <- p; spaces; return a}
reserved :: String -> Parser String
reserved s = token (string s)
number :: Parser Int
number = do
s <- string "-" <|> return []
cs <- some digit
return $ read (s ++ cs)