(<|>) :: Alternative f => f a -> f a -> f a
(<*) :: Applicative f => f a -> f b -> f a
(*>) :: Applicative f => f a -> f b -> f b(<|>)lets us pick whichever of left and right is successful(<*)lets us evaluatef aandf breturning only the result off a(it's strict inf bandf b)(*>)is(<*)the opposite of(<*)- all of these are in
Control.Applicative
Think of a cursor moving through a string-like object. Parser combinators tell the cursor when to move and what to do with what it encounters.
Example:
char '1'tells the cursor "give me the character '1'".
Parser combinators themselves don't do anything -- they only describe how to do things. To do
something, we need some function (pseudocode) Parser a -> ... -> String -> Result a. This function
frequently starts with parse. In trifecta, it's parseString or parseByteString if you're feeling
fancy. In attoparsec it's parse and parseOnly ('parseOnly stops when it's done and returns an
Either, parse returns a Result holding the remaining things to parse and what was successfully
parsed).
Example:
parseString (char '1') mempty :: String -> Result Char
parseString (char '1') mempty "2" :: Result Char
parseString (char '1') mempty "1" :: Result Char(<|>) is from the Alternative typeclass, with the operator exposed in Control.Applicative.
Here's what it looks like for Maybe:
instance Alternative Maybe where
empty = Nothing
Nothing <|> r = r
l <|> _ = l
The Alternative typeclass also provides some and many methods. some repeats a parser at
least once, while many repeats a parser any number of times (including zero):
parseString (some integer) mempty "a" -- Failure
parseString (some integer) mempty "a" -- Success []Just don't. The parsers in Text.Trifecta.Char are tokenizers already. If you need custom
tokenizing, worry about how to do that then.
Because parser combinators are build off of parsing typeclasses, you can have function signatures like:
parseFraction :: (Monad m, TokenParsing m) => m Rationaland maintain simultaneous support for whatever parsers anyone has written or will write now or in the future.
You can encounter the problem where you want
real world data -> YourDataType
and
YourDataType -> real world data
These are unmarshalling and marshalling, respectively.
We can do this with aeson by providing FromJSON and ToJSON typeclasses for
our datatype, but it's sort of boring compared to unmarshalling problems in
Advent of Code and they're autoderivable because we live in the future, so
skipping.
This isn't a very good one but here it is