First, just some quick context. I'm going through the Haskell Programming From First Principles book, and ran into the following exercise.
Try writing a Parser that does what
stringdoes, but usingchar.
I couldn't figure it out, so I checked out the source for the implementation. I'm currently trying to wrap my head around it. Here it is:
class Parsing m => CharParsing m where
-- etc.
string :: CharParsing m => String -> m String
string s = s <$ try (traverse_ char s) <?> show s
My questions are as follows, from most to least specific.
Why is
shownecessary?Why is
s <$necessary? Doesn'ttraverse char s <?> swork the same? In other words, why do we throw away the results of the traversal?What is going on with the traversal? I get what a list traversal does, so I guess I'm confused about the Applicative/Monad instances for Parser. On a high level, I get that the traversal applies
char, which has typeCharParsing m => Char -> m Char, to every character in strings, and then collects all the results into something of typeParser [Char]. So the types make sense, but I have no idea what's going on in the background.
Thanks in advance!
Because
showing a string (or aText, etc.) escapes special characters, which makes sense for error messages:The result of the parse is unnecessary because we know in advance that it would be
s(if the parse were successful).traversewould needlessly reconstructsfrom the results of parsing each individual character. In general, if the results are not needed it is a good idea to usetraverse_(which just combines the effects, discarding the results without trying to rebuild the data structure) rather thantraverse, so that is likely why the function is written the way it is.traverse_ char s(traverse_, and nottraverse, as explained above) is a parser. It tries to parse, in order, each character ins, while discarding the results, and it is built by sequencing parsers for each character ins. It may be helpful to remind thattraverse_is just a fold which uses(*>):