A new Swift video series exploring functional programming and more.
#57 • Monday May 13, 2019 • Subscriber-only

What Is a Parser?: Part 2

Now that we’ve looked at a bunch of parsers that are at our disposal, let’s ask ourselves what a parser really is from the perspective of functional programming and functions. We’ll take a multi-step journey and optimize using Swift language features.

This episode builds on concepts introduced previously:

#57 • Monday May 13, 2019 • Subscriber-only

What Is a Parser?: Part 2

Now that we’ve looked at a bunch of parsers that are at our disposal, let’s ask ourselves what a parser really is from the perspective of functional programming and functions. We’ll take a multi-step journey and optimize using Swift language features.

This episode builds on concepts introduced previously:


Subscribe to Point‑Free

This episode is for subscribers only. To access it, and all past and future episodes, become a subscriber today!

See subscription optionsorLog in

Sign up for our weekly newsletter to be notified of new episodes, and unlock access to any subscriber-only episode of your choosing!

Sign up for free episode

Introduction

The manual, hand-rolled coordinate parsing function we made last time is already pretty complicated, and capturing every edge case will make it more complicated still.

But that’s not even the worst part. The worst part is that this parse function is a one-off, ad hoc solution to parsing the very specific format of latitude/longitude coordinates. There is nothing inside the body that is reusable outside of this example.

We’re definitely seeing how tricky and subtle parsing can be, and it’s easy to end up with a complex function that would need to be studied very carefully to understand what it’s doing, and even then it would be easy to overlook the potential bugs that lurk within.

Let’s back up and formally state what the problem of parsing is and analyze it from the perspective of functional programming and functions.

Subscribe to Point-Free

👋 Hey there! Does this episode sound interesting? Well, then you may want to subscribe so that you get access to this episodes and more!


Exercises

  1. Create a parser char: Parser<Character> that will parser a single character off the front of the input string.

  2. Create a parser whitespace: Parser<Void> that consumes all of the whitespace from the front of the input string. Note that this parser is of type Void because we probably don’t care about the actual whitespace we consumed, we just want it consumed.

  3. Right now our int parser doesn’t work for negative numbers, for example int.run("-123") will fail. Fix this deficiency in int.

  4. Create a parser double: Parser<Double> that consumes a double from the front of the input string.

  5. Define a function literal: (String) -> Parser<Void> that takes a string, and returns a parser which will parse that string from the beginning of the input. This exercise shows how you can build complex parsers: you can use a function to take some up-front configuration, and then use that data in the definition of the parser.

  6. In this episode we mentioned that there is a correspondence between functions of the form (A) -> A and functions (inout A) -> Void. We even covered this in a previous episode, but it is instructive to write it out again. So, define two functions toInout and fromInout that will transform functions of the form (A) -> A to functions (inout A) -> Void, and vice-versa.


References

Chapters
Introduction
00:05
What is a parser?
01:00
Parsing as a multi-step process
07:33
Optimized parsing with inout
13:43
Optimized parsing with substring
16:10
Till next time
19:08