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 grasped it yet, but I thought I would share the current state of my knowledge, however close I am to becoming 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 encountered them have become useful, and how they have 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 simply boxes that hold a value and allow one to unwrap it, apply a function, wrap it again, and continue. I followed one of the tutorials that showed the evolution from Functors through Applicatives to Monads, complete with pictures. It made perfect sense while I thought about the list mapping, reducing and filtering. With my experience in LINQ with C#, RxJava, and simple list operations in Kotlin, I understand 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 flatMap and map are very similar to me. When I end up with a list of lists, instead of mapping and flattening, I use flatMap, but I still don’t fully grasp the abstract power of it beyond 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 include logging errors, printing to the console, or launching 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 category theory. It must have the type constructor, type converter (unit) and combinator (bind). Moreover, it must obey three laws: left identity, right identity, and associativity. This explanation doesn’t help build intuition, but it could help 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 have created my first Monads in languages such as Haskell, Scala, and possibly Kotlin. Wish me luck in my journey.