Parsing
Tip
Understanding parser combinators is a prerequisite for this module. See here for information.
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 |
|
- It's often useful to make a custom type for errors specific to the domain in question.
asum
comes from theAlternative
typeclass:asum [x,y,z]
=x <|> y <|> z
.either :: (a -> c) -> (b -> c) -> Either a b -> c
is a useful function for handling anEither X Y
.- Viewed with the Haskell Language Server, this will be underlined in blue, with a simplification suggested.
- Like anything else in Haskell, parsers are just values, so it's possible (and idiomatic) to put them in a list and then fold the list.
- Observe how the parser as a whole is built out of smaller parsers.
"place"
is itself a parser, thanks to OverloadedStrings.a <$> b = fmap a b
. That is:<$>
is an infix synonym forfmap
. Example withconst
:fmap (const 1) [1,2,3,4] = [1,1,1,1]
- We abstract some boilerplate with a function that makes a simple parser given a name and return value.
eof
only succeeds at the end of a line, so ensures there are no more characters left.return
is not a keyword. Here, it converts anInstruction
into aParser Instruction
, namely the trivial parser that does nothing and immediately returns anInstruction
. ThisParser Instruction
is the final parser in the sequence of parsers in thedo-notation
code block.- do-notation used to build a complex parser out of a series of simpler ones and their results.
- Explicit imports like this are useful both for readability and to avoid namespace clashes.
- Another way to avoid namespace clashes. Common for both
Data.Map
andData.Text
. - Void is the empty type. This says that the custom error type is
Void
(i.e. doesn't exist), and that the type of the input sequence isText
.
Analysis¶
This module exists to parse user input on the command line into the Instruction
type. Parsing directly into a custom type is idiomatic Haskell because it handles errors nicely: either parsing succeeds and you're guaranteed to get an Instruction
, or you get an interpretable parse failure.
Note the use of word
, a function which takes a parser and returns a new parser that handles white space. This abstracts white space handling to a single function, and makes for clean, idiomatic parsing.
parsePiece
¶
parsePiece :: Ord a => Parsec a Text Piece
parsePiece = do
color <- word $ (const White <$> "white") <|> (const Black <$> "black")
pieceType <-
word $
try (const Bishop <$> "bishop")
<|> try (const King <$> "king")
<|> try (const Queen <$> "queen")
<|> try (const Knight <$> "knight")
<|> try (const Rook <$> "rook")
<|> try (const Pawn <$> "pawn")
return (Piece pieceType color)
parseRank
¶
Last update:
January 18, 2023
Created: August 18, 2022
Created: August 18, 2022