The term “monad” is often invoked when describing patterns in functional programming. Yet explanations typically swing between high-level metaphors and deep mathematical abstractions. Each approach offers part of the picture, intuition without precision, or rigor without intuition but seldom both.
Monads can be idealized as a container (albeit is a flawed metaphor) or context holding a value (or multiple values, or no value), but in some cases we will get into later on it’s better to think of it as a recipe or deferred computation for producing a value. At the heart of monadic programming is the idea that you write one function, say, f(x) = x + 1 , and then reuse it across different contexts without rewriting control-flow logic.
Two Flavours: Result vs Recipe
While all monads provide a computational context, they generally fall into two flavors:
Monads as “Results”: These represent a value that has already been computed, but with extra context. List
is a result with the context. is the result of a computation with the context of “possible optionalness.” For these, the “container” metaphor is a useful, if limited, starting point. Monads as “Recipes”: These represent a computation that has not happened yet. They are a blueprint for producing a value. C#’s Task
Sometimes, you can mix the flavors. In this post, we will focus on the first category to build our core intuition. We’ll start with List and Maybe to understand the mechanics of map and flatMap on concrete results. In Part 2, we’ll see how these same patterns unlock immense power when applied to “recipe” monads like Task .
List : Map & FlatMap in Practice
To an OOP developer, monadic types ( List
A good example of a monad is a list. You’re likely very familiar with lists and working with lists.
... continue reading