Skip to content

Commit 92d60c6

Browse files
committed
[Parsers] End Appar chapter
1 parent dc5a540 commit 92d60c6

File tree

1 file changed

+105
-1
lines changed

1 file changed

+105
-1
lines changed

en/lessons/parsers/appar.md

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,108 @@ title: Appar
55

66
{% include toc.html %}
77

8-
https://hackage.haskell.org/package/appar
8+
[Appar](https://hackage.haskell.org/package/appar) is different from the other
9+
libraries such that, they are monadic, while `appar` is applicative.
10+
See [this](https://stackoverflow.com/a/7863380/1599054) to have a good explanation
11+
between the two.
12+
13+
# Definition
14+
15+
Let's start with the definition:
16+
17+
```haskell
18+
data MkParser inp a = P {
19+
runParser :: inp -> (Maybe a, inp)
20+
}
21+
```
22+
23+
It really looks like `attoparsec`'s `ZeptoT`, except that the `Monad` is inside
24+
the result.
25+
26+
Let's see the instances:
27+
28+
```haskell
29+
instance Functor (MkParser inp) where
30+
f `fmap` p = return f <*> p
31+
32+
instance Applicative (MkParser inp) where
33+
pure a = P $ \bs -> (Just a, bs)
34+
(<*>) = ap
35+
36+
instance Alternative (MkParser inp) where
37+
empty = mzero
38+
(<|>) = mplus
39+
40+
instance Monad (MkParser inp) where
41+
return = pure
42+
p >>= f = P $ \bs -> case runParser p bs of
43+
(Nothing, bs') -> (Nothing, bs')
44+
(Just a, bs') -> runParser (f a) bs'
45+
46+
instance MonadPlus (MkParser inp) where
47+
mzero = P $ \bs -> (Nothing, bs)
48+
p `mplus` q = P $ \bs -> case runParser p bs of
49+
(Nothing, bs') -> runParser q bs'
50+
(Just a, bs') -> (Just a, bs')
51+
```
52+
53+
One thing surprising is the `Monad` instance for an applicative parser, we can
54+
conclude that the '`Applicative`ness' of the library cames from the lack of
55+
shortcut, more than the implemented solution.
56+
57+
# Construction
58+
59+
How are parsers built:
60+
61+
```haskell
62+
class Eq inp => Input inp where
63+
-- | The head function for input
64+
car :: inp -> Char
65+
-- | The tail function for input
66+
cdr :: inp -> inp
67+
-- | The end of input
68+
nil :: inp
69+
-- | The function to check the end of input
70+
isNil :: inp -> Bool
71+
72+
satisfy :: Input inp => (Char -> Bool) -> MkParser inp Char
73+
satisfy predicate = P sat
74+
where
75+
sat bs
76+
| isNil bs = (Nothing, nil)
77+
| predicate b = (Just b, bs')
78+
| otherwise = (Nothing, bs)
79+
where
80+
b = car bs
81+
bs' = cdr bs
82+
```
83+
84+
A bit abstract (and a bit lisp-like), but without surprises.
85+
86+
Anothor interesting one:
87+
88+
```haskell
89+
try :: MkParser inp a -> MkParser inp a
90+
try p = P $ \bs -> case runParser p bs of
91+
(Nothing, _ ) -> (Nothing, bs)
92+
(Just a, bs') -> (Just a, bs')
93+
```
94+
95+
As expected: the parser is ran, if it succeeds, the input is consumer, or the
96+
original input is returned.
97+
98+
# Running the parser
99+
100+
As we can expect, running the pparser will only consist in getting the computed
101+
result:
102+
103+
```haskell
104+
parse :: Input inp => MkParser inp a -> inp -> Maybe a
105+
parse p bs = fst (runParser p bs)
106+
```
107+
108+
# Conclusion
109+
110+
`appar` is really simple, but it is unique in the sense that it prevent
111+
context-dependant parsing.
112+

0 commit comments

Comments
 (0)