A Monad

I've recently had several discussions about Monads and Category Theory. It took me a long time to grok monads, until I explored their core reason for being. So I felt it would be a good idea to put down my thoughts in one place. I always try to begin with a more cohesive mental model of the problems computer science is trying to solve. So things like monads, functors, etc, come out of category theory, which is a mathematical formalism that exists outside of computer science. Essentially mathematicians are trying to take some state and transform it to another state.

If you think about computation in the abstract, focusing on type systems, languages like Haskell (and Clojure with extra tools) encourage a very disciplined way about data typing and representation, and data transformation. So this is the kind of math that lets you think about how acoustic waves get transformed into digital representations. Or how is video captured, and what algorithms can we run over top of the data to flip it, or get a negative of an image, etc? So what is an image, and how would we represent it digitally, in order to do some of these interesting transformations. Those are the math functions which a good computer program will provide. The categories are the state and the functors are the transformations (ex. type systems try to formalize the categories, monads are functors, etc). Using category theory math in programming is an attempt at having a provable system.

From Technopedia: A monad is an abstract data type constructor that is used to represent computations in functional programming. They allow programmers to chain actions together to build a pipeline. The monad assigns additional processing rules to each action in the program.

  1. A monad is created by defining two operations ("bind" and "return") and a type constructor ("M").
  2. The "return" operation takes a value from a plain type and puts it into a type "M" monadic container.
  3. Then, the "bind" operation does the opposite by extracting the original value from the container and passing it to the associated next function in the pipeline.

I also write this down to cement my own clarity on the issue. I want to highlight when and why we'd want to use this kind of math, and more importantly, my opinion on how a programmer needs to think. A useful mindset is important when deconstructing the essence of any given problem. Think of the value of having a system we can prove is always correct for a given set of concurrent, distributed inputs (think military, finance, global communications, etc).

And remember, humans don't really know how to compute (see here and here). We understand biology or quantum physics better because those natural laws are concrete and observable. Human consciousness and cognition (ie, computation) are still unknown to us. Hope this helps :)