We are extremely excited to start this next series of episodes. This topic is more than 4 years in the making. We first started experimenting with these concepts before even launching Point-Free and we’ve been developing, re-developing and refining them over and over and over ever since.
Our series of episodes on parsers is some of our most popular content, second only to our Composable Architecture episodes. People in the community have built some really amazing tools with the parsing library we open sourced over a year ago, including music notation parsers, math expression parsers, XML parsers, and even full-on programming language parsers.
Although we have gone really deep into parser topics, including composition, performance, low-level string processing, API ergonomics, error handling, and more, there’s still a huge topic that we haven’t touched upon at all. When building a parser we spend a lot of time getting to know all of the subtleties and edge cases of the input we are trying to parse. This can actually be quite a significant amount of work, and when it’s all done it is quite satisfying to see it turn nebulous blobs of input values into well-structured output values.
But, often you need to turn your well-structured data back into the nebulous blob of data. We call this inverse process “printing”.
For example, after much work you may come up with a way to parse a custom textual format into some well-structured Swift data type that is used in your application. But then, at a later time, you decide to add some editing capabilities to the application. The instant we do this we are confronted with the problem of how to turn values of your first-class Swift data type back into an unstructured string so that we can save that data back to disk or send it to a server.
Many of Apple’s parsers work this way too. Not only can you decode nebulous JSON data into a first-class type, but you can also encode values of the type back into JSON data. Further, not only can date and number formatters parse a string into a date or number, but they can also turn those values back into a formatted string. So even Apple’s APIs recognize that once you have accomplished a parsing problem there is a corresponding printing or formatting problem left to be solved.
So, the problem of trying to reverse the process of parsing is important enough that we should definitely discuss it. Turns out, we can develop the theory of printing in parallel to the theory of parsing. It allows us to tackle the problem of printing in small, bite-sized units and then piece together all the parts to form a large, complex printer.
That already sounds cool, but the most amazing part of this story is that we can build parsers and printers simultaneously. If you are careful enough, then the very act of describing your parser will simultaneously provide you with a printer such that if you parse and then print you get roughly the “same” thing you started with, and similarly if you print and then parse.