Parse
I had one of those moments last week.
One of those “how did I never see this before” moments.
Although I have a suspicion based on a talk I gave a couple of years ago at NSSpain that it was more of a “I understood this at one time, how did I forget it” moments.
Anyway, I’d reread a part of Paul Chiusano and Runar Bjarnason’s book Functional Programming in Scala. I like and recommend this book even for those of us who don’t code in Scala.
I was implementing an example of a Parser in Swift. Something like this:
struct Parser<A> {
let parse: (Substring) -> (A, Substring)
}
They have an example of a Random Number Generator in an earlier chapter. You create an RNG that returns a random Int. Then you use map()
to transform it into an RNG that returns Double
s or Bool
s. Then you learn to use flatMap()
to return the next five random somethings or the first random something that meets a condition. This is a common example for State patterns.
Later they are looking at Parser combinators and I translated it to Swift as something like the above.
Then I stopped.
This looks a lot like State.
struct State<S, A> {
let run: (S) -> (A, S)
}
In fact for Random Number Generators we defined a type named RNG
and created our Random number generator that returned A
s as being a typealias Random<A> = State<RNG, A>
.
So Parser
could be seen as essentially typealias Parser<A> = State<Substring, A>
where we replace run
with parse
.
All of a sudden Parser Combinators felt more like something that belonged to a family and not some new concept.
So that’s why we struggle with these abstractions - at some point we look at a new concept and say, “wait, that looks just like this other thing.”
This month’s comic is not very visual. Just the “mind-blown” emoji because I couldn’t find the “repeatedly smacking myself in the head for not seeing it sooner” emoji.
I love that our understanding of these notions deepens over time.