You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -22,26 +23,41 @@ Here is a basic tutorial introduction to monadic parsing with this package.
22
23
23
24
### Parsers
24
25
25
-
A parser turns a string into a data structure. Parsers in this library have the type `Parser s a`, where `s` is the type of the input string, and `a` is the type of the data which the parser will produce on success. `Parser s a` is a monad. It’s defined in the module `Text.Parsing.Parser`.
26
+
A parser turns a string into a data structure. Parsers in this library have the type `Parser s a`, where `s` is the type of the input string, and `a` is the type of the data which the parser will produce on success. `Parser s` is a monad. It’s defined in the module `Text.Parsing.Parser`.
26
27
27
-
Monads can be used to provide context for a computation, and that’s how we use them in monadic parsing. The context provided by the `Parser` monad is *the parser’s current location in the input string*. Parsing starts at the beginning of the input string.
28
+
Monads can be used to provide context for a computation, and that’s how we use them in monadic parsing.
29
+
The context provided by the `Parser s` monad is __the parser’s current location in the input string__.
30
+
Parsing starts at the beginning of the input string.
28
31
29
-
Parsing requires two more capabilities: *choice* and *failure*.
32
+
Parsing requires two more capabilities: __alternative__ and __failure__.
30
33
31
-
We need *choice* to be able to make decisions about what kind of thing we’re parsing depending on the input which we encouter. This is provided by the `Alt` typeclass instance of the `Parser` monad, particularly the `<|>` operator. That operator will first try the left parser and if that fails, then it will backtrack the input string and try the right parser.
34
+
We need __alternative__ to be able to choose what kind of thing we’re parsing depending
35
+
on the input which we encounter. This is provided by the `<|>` “alt”
36
+
operator of the `Alt` typeclass instance of the `Parser s` monad.
37
+
The expression `p_left <|> p_right` will first try the `p_left` parser and if that fails
38
+
__and consumes no input__ then it will try the `p_right` parser.
32
39
33
-
We need *failure* in case the input stream is not parseable. This is provided by the `fail` function, which calls the `throwError` function of the `MonadThrow` typeclass instance of the `Parser` monad. The result of running a parser has type `Either ParseError a`, so if the parse succeeds then the result is `Right a` and if the parse fails then the result is `Left ParseError`.
40
+
We need __failure__ in case the input stream is not parseable. This is provided by the `fail`
41
+
function, which calls the `throwError` function of the `MonadThrow` typeclass instance of
42
+
the `Parser s` monad.
34
43
35
-
36
-
### Running a parser
37
-
38
-
To run a parser, call the function `runParser :: s -> Parser s a -> Either ParseError a` in the `Text.Parsing.Parser` module, and supply it with an input string and a parser.
44
+
To run a parser, call the function `runParser :: s -> Parser s a -> Either ParseError a` in
45
+
the `Text.Parsing.Parser` module, and supply it with an input string and a parser.
46
+
If the parse succeeds then the result is `Right a` and if the parse fails then the
47
+
result is `Left ParseError`.
39
48
40
49
### Primitive parsers
41
50
42
-
Each type of input string needs primitive parsers. Primitive parsers for input string type `String` are in the `Text.Parsing.Parser.String` module. We can use these primitive parsers to write other `String` parsers.
51
+
Each type of input string needs primitive parsers.
52
+
Primitive parsers for input string type `String` are in the `Text.Parsing.Parser.String` module.
53
+
We can use these primitive parsers to write other `String` parsers.
43
54
44
-
Here is a parser `ayebee :: Parser String Boolean` which will accept only two input strings: `"ab"` or `"aB"`. It will return `true` if the `b` character is uppercase. It will return `false` if the `b` character is lowercase. It will fail with a `ParseError` if the input string is anything else. This parser is written in terms of the primitive parser `char :: Parser String Char`.
55
+
Here is a parser `ayebee :: Parser String Boolean` which will accept only two input
56
+
strings: `"ab"` or `"aB"`.
57
+
It will return `true` if the `b` character is uppercase.
58
+
It will return `false` if the `b` character is lowercase.
59
+
It will fail with a `ParseError` if the input string is anything else.
60
+
This parser is written in terms of the primitive parser `char :: Parser String Char`.
45
61
46
62
```purescript
47
63
ayebee :: Parser String Boolean
@@ -61,24 +77,33 @@ and then the parser will succeed and return `Right true`.
61
77
62
78
#### [✨ Run the `ayebee` parser in your browser on *Try PureScript!*](https://try.purescript.org/?github=/purescript-contrib/purescript-parsing/main/docs/examples/QuickStart.purs)
63
79
64
-
When you write a real parser you will usually want to return a more complicated data structure than a single `Boolean`. See [*Parse, don't validate*](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/).
65
-
66
80
### More parsers
67
81
68
82
There are other `String` parsers in the module `Text.Parsing.Parser.Token`, for example the parser `letter :: Parser String Char` which will accept any single alphabetic letter.
69
83
70
84
### Parser combinators
71
85
72
-
A parser combinator is a function which takes a parser as an argument and returns a new parser. The `many` combinator, for example, will repeat a parser as many times as it can. So the parser `many letter` will have type `Parser String (Array Char)`. Parser combinators are in this package in the module `Text.Parsing.Parser.Combinators`.
86
+
A parser combinator is a function which takes a parser as an argument and returns a new parser. The `many` combinator, for example, will repeat a parser as many times as it can. So the parser `many letter` will have type `Parser String (Array Boolean)`. Running that parser
87
+
88
+
```purescript
89
+
runParser "aBabaB" (many ayebee)
90
+
```
91
+
92
+
will return `Right [true, false, true]`.
93
+
94
+
Parser combinators are in this package in the module `Text.Parsing.Parser.Combinators`.
73
95
74
96
## Further reading
75
97
76
-
Here is the original short classic [FUNCTIONAL PEARLS *Monadic Parsing in Haskell*](https://www.cs.nott.ac.uk/~pszgmh/pearl.pdf) by Graham Hutton and Erik Meijer.
98
+
Here is the original short classic [FUNCTIONAL PEARLS *Monadic Parsing in Haskell*](https://www.cs.nott.ac.uk/~pszgmh/pearl.pdf) by Graham Hutton and Erik Meijer.
77
99
78
100
[*Revisiting Monadic Parsing in Haskell*](https://vaibhavsagar.com/blog/2018/02/04/revisiting-monadic-parsing-haskell/) by Vaibhav Sagar is a reflection on the Hutton, Meijer FUNCTIONAL PEARL.
79
101
80
102
[*Parse, don't validate*](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) by Alexis King is about what it means to “parse” something, without any mention of monads.
81
103
104
+
[*Parsec: “try a <|> b” considered harmful*](http://blog.ezyang.com/2014/05/parsec-try-a-or-b-considered-harmful/) by Edward Z. Yang is about how to decide when to backtrack
105
+
from a failed alternative.
106
+
82
107
There are lots of other great monadic parsing tutorials on the internet.
0 commit comments