Skip to content

Commit 13f940a

Browse files
committed
Use instances of Alternative with parsers
1 parent 9648826 commit 13f940a

File tree

2 files changed

+192
-28
lines changed

2 files changed

+192
-28
lines changed

13-monadic-parsing/13.07-handling-space.hs

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,6 @@ item = P $ \inp ->
1212
[] -> []
1313
(x:xs) -> [(x, xs)]
1414

15-
instance Functor Parser where
16-
fmap f p = P $ \inp ->
17-
case parse p inp of
18-
[] -> []
19-
[(v, out)] -> [(f v, out)]
20-
21-
instance Applicative Parser where
22-
pure v = P $ \inp -> [(v, inp)]
23-
24-
pf <*> px = P $ \inp ->
25-
case parse pf inp of
26-
[] -> []
27-
[(f, out)] -> parse (fmap f px) out
28-
29-
instance Monad Parser where
30-
p >>= f = P $ \inp ->
31-
case parse p inp of
32-
[] -> []
33-
[(v, out)] -> parse (f v) out
34-
35-
instance Alternative Parser where
36-
empty = P $ \inp -> []
37-
38-
p <|> q = P $ \inp ->
39-
case parse p inp of
40-
[] -> parse q inp
41-
[(v, out)] -> [(v, out)]
42-
4315
sat :: (Char -> Bool) -> Parser Char
4416
sat p = do
4517
x <- item
@@ -94,6 +66,8 @@ int = do
9466
n <- nat
9567
return (-n) <|> nat
9668

69+
-- | The `token` function defines a new primitive that ignores any space before
70+
-- and after applying a parser for a token.
9771
token :: Parser a -> Parser a
9872
token p = do
9973
space
@@ -113,6 +87,8 @@ integer = token int
11387
symbol :: String -> Parser String
11488
symbol xs = token (string xs)
11589

90+
-- | The `nats` parser is defined for a non-empty list of natural numbers that
91+
-- ignores spacing around tokens.
11692
nats :: Parser [Int]
11793
nats = do
11894
symbol "["
@@ -122,3 +98,31 @@ nats = do
12298
natural
12399
symbol "]"
124100
return (n:ns)
101+
102+
instance Functor Parser where
103+
fmap f p = P $ \inp ->
104+
case parse p inp of
105+
[] -> []
106+
[(v, out)] -> [(f v, out)]
107+
108+
instance Applicative Parser where
109+
pure v = P $ \inp -> [(v, inp)]
110+
111+
pf <*> px = P $ \inp ->
112+
case parse pf inp of
113+
[] -> []
114+
[(f, out)] -> parse (fmap f px) out
115+
116+
instance Monad Parser where
117+
p >>= f = P $ \inp ->
118+
case parse p inp of
119+
[] -> []
120+
[(v, out)] -> parse (f v) out
121+
122+
instance Alternative Parser where
123+
empty = P $ \inp -> []
124+
125+
p <|> q = P $ \inp ->
126+
case parse p inp of
127+
[] -> parse q inp
128+
[(v, out)] -> [(v, out)]
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import Control.Applicative
2+
import Data.Char
3+
4+
newtype Parser a = P (String -> [(a, String)])
5+
6+
-----------------------------------------------------------------------------
7+
-- expr ::= term (+ expr | ∊)
8+
-- term ::= factor (* term | ∊)
9+
-- factor ::= ( expr ) | nat
10+
-- nat ::= 0 | 1 | 2 | ...
11+
-----------------------------------------------------------------------------
12+
13+
expr :: Parser Int
14+
expr = do
15+
t <- term
16+
do
17+
symbol "+"
18+
e <- expr
19+
return (t + e) <|> return t
20+
21+
term :: Parser Int
22+
term = do
23+
f <- factor
24+
do
25+
symbol "*"
26+
t <- term
27+
return (f * t) <|> return f
28+
29+
factor :: Parser Int
30+
factor = do
31+
symbol "("
32+
e <- expr
33+
symbol ")"
34+
return e <|> natural
35+
36+
eval :: String -> Int
37+
eval xs = case (parse expr xs) of
38+
[(n, [])] -> n
39+
[(_, out)] -> error ("Unused input " ++ out)
40+
[] -> error "Invalid input"
41+
42+
parse :: Parser a -> String -> [(a, String)]
43+
parse (P p) inp = p inp
44+
45+
item :: Parser Char
46+
item = P $ \inp ->
47+
case inp of
48+
[] -> []
49+
(x:xs) -> [(x, xs)]
50+
51+
sat :: (Char -> Bool) -> Parser Char
52+
sat p = do
53+
x <- item
54+
if p x
55+
then return x
56+
else empty
57+
58+
digit :: Parser Char
59+
digit = sat isDigit
60+
61+
lower :: Parser Char
62+
lower = sat isLower
63+
64+
upper :: Parser Char
65+
upper = sat isUpper
66+
67+
letter :: Parser Char
68+
letter = sat isAlpha
69+
70+
alphanum :: Parser Char
71+
alphanum = sat isAlphaNum
72+
73+
char :: Char -> Parser Char
74+
char x = sat (== x)
75+
76+
string :: String -> Parser String
77+
string [] = return []
78+
string (x:xs) = do
79+
char x
80+
string xs
81+
return (x:xs)
82+
83+
ident :: Parser String
84+
ident = do
85+
x <- lower
86+
xs <- many alphanum
87+
return (x:xs)
88+
89+
nat :: Parser Int
90+
nat = do
91+
xs <- some digit
92+
return (read xs)
93+
94+
space :: Parser ()
95+
space = do
96+
many (sat isSpace)
97+
return ()
98+
99+
int :: Parser Int
100+
int = do
101+
char '-'
102+
n <- nat
103+
return (-n) <|> nat
104+
105+
token :: Parser a -> Parser a
106+
token p = do
107+
space
108+
v <- p
109+
space
110+
return v
111+
112+
identifier :: Parser String
113+
identifier = token ident
114+
115+
natural :: Parser Int
116+
natural = token nat
117+
118+
integer :: Parser Int
119+
integer = token int
120+
121+
symbol :: String -> Parser String
122+
symbol xs = token (string xs)
123+
124+
nats :: Parser [Int]
125+
nats = do
126+
symbol "["
127+
n <- natural
128+
ns <- many $ do
129+
symbol ","
130+
natural
131+
symbol "]"
132+
return (n:ns)
133+
134+
instance Functor Parser where
135+
fmap f p = P $ \inp ->
136+
case parse p inp of
137+
[] -> []
138+
[(v, out)] -> [(f v, out)]
139+
140+
instance Applicative Parser where
141+
pure v = P $ \inp -> [(v, inp)]
142+
143+
pf <*> px = P $ \inp ->
144+
case parse pf inp of
145+
[] -> []
146+
[(f, out)] -> parse (fmap f px) out
147+
148+
instance Monad Parser where
149+
p >>= f = P $ \inp ->
150+
case parse p inp of
151+
[] -> []
152+
[(v, out)] -> parse (f v) out
153+
154+
instance Alternative Parser where
155+
empty = P $ \inp -> []
156+
157+
p <|> q = P $ \inp ->
158+
case parse p inp of
159+
[] -> parse q inp
160+
[(v, out)] -> [(v, out)]

0 commit comments

Comments
 (0)