Road to understanding Monads
They say that once you understand the Monads, first, you lose the ability to explain it, and second, you write a blog post about it. Even though I’ve been grasping the concept for a few years already, I haven’t honestly gotten it yet, but I thought I would dump the current state of my knowledge, however close I am to being a conscious and happy user of this concept.
Multiple people say it is obvious once it clicks. I’m still waiting for this actual “aha” moment. I had a few little clicks in the past that made me think this was it, but once I got into the real-life examples, it became blurry again. The abstraction in my head was never enough to cover all the cases and be helpful in day-to-day development. Nevertheless, I keep trying because I see how much the other functional concepts that seemed useless when I first met them became useful and how they changed my way of coding and looking at the craft or even the art of programming. Immutability, pure functions, higher-order functions, and currying, to name a few, made me a much better programmer. I’m sure they guided my career and interests in the direction of software architecture in general.
Back to the elephant in the room, Monads, I will share the clicks that made me think I understood the concept but always left some unsolved questions.
Monads are just simple boxes that hold something and allow one to unwrap the value, apply a function, wrap it again and keep going. I followed one of the tutorials showing the evolution from Functors through the Applicatives to Monads with pictures. It made perfect sense while I thought about the list mapping, reducing and filtering. With my experience with LINQ in C#, rxJava and simple list operations in kotlin, I get how useful it could be. However, with only this analogy in mind, I still lack an understanding of the difference between Functor and Monad. Both
map are very similar to me. When I end up with a list of lists, instead of mapping and flattening, I do flatMap, but I still don’t get the real abstract power of it outside the simple realm of lists.
Monads are just a computable context that decorates something. This explanation, built on the “box” analogy, shed new light on my understanding. You can compose some simple things like adding numbers but at the same time apply some functions with side effects without polluting the internal operations with ugly, complicated code. Inside we have only pure computations. Outside may be anything like logging errors, printing to the console, or launching the missiles. As long as it is encapsulated in the computable context, it can be isolated from the pure domain logic. This explains types such as Maybe, Either etc. Again, it sounds simple and makes me understand why somebody used the burrito analogy, but in practice, I still don’t fully feel the power that everybody mentions.
Monads are the monoids in the category of endofunctors, a purely mathematical concept from the category theory. It must have the type constructor, type converter (unit) and combinator (bind). Moreover, it has to obey three laws: left identity, right identity and associativity. This explanation doesn’t help build the intuition but could help to check if something I create is an actual Monad that I can count on.
This is the state of my knowledge and understanding. I hope to build an intuition on top of that and write something more specific soon, once I make my first Monads in languages such as Haskell, Scala and possibly kotlin. Wish me luck in my journey.