Last week we concluded our recap of parsers to bring everyone up to speed on what a parser is, how functional programming defines parsers, and how to decompose a large, complex problem into many small pieces. Today we’ll begin talking about some new topics, starting with how to provide a better interface to the zip
function on parsers.
Recall that zip
is a parser combinator whose job is to allow you to run many parsers on an input string. Each parser can consume a bit of the input string to produce a value of some first class data type, and once all the zipped parsers have run it delivers a tuple of all those values to you.
We’ve used the zip
function quite a bit already. It’s probably one of the most important tools for building up complex parsers from simpler ones. And interestingly, the idea of “zipping” is not unique to parsing, there are a lot of data structures out there that support zip-like operations. First of all, probably most widely known, the Swift standard library comes with a zip
defined on collections, but we’ve seen it also makes sense to define zip
on optionals, results, random number generators, asynchronous values, Combine publishers, and more.
However, there is one thing about zipping parsers that’s a little different from all of those other examples. When parsing we are often consuming a bit from the input string and then completely discarding the result of that parsing. That is, the parser wants to consume some of the input but it doesn’t produce anything of interest to the user of the parser. For example, we’ve many times parsed a literal string off the front of the input, such as consuming a comma or a space, but those parsers only produce a Void
value, hence nothing significant.
This is pretty unique to parsers. We aren’t often dealing with arrays of void values, or random generators of void values, or even asynchronous void values, but for parsers it is legitimately useful to have a void parser, and even quite common. And because of this oddity, our usages of zip
when plugging together many parsers looked a little strange.
So, we are going to take another look at the zip
function on parsers and see if we can come up with another formulation of zip
that is a little friendlier to parsers. We will discover an API that not only fixes the problem we just described, but is also more fluent in the way it reads, and even requires us to have fewer overloads to handle the kinds of parsers we have been working with so far.