Monads — Examples and Definitions
Examples
We, Swift programmers, are in touch and use some monads without even know that they are classified as such: Arrays (as well as all other Sequences) and Optionals are both valid examples for this statement.
There are also frameworks that implement other monads: RxSwift, a reactive programming framework implements Subjects (objects that can be observed and observe at the same time) as those.
They are even more useful in pure functional languages in order to deal specially with controlled side-effects. Chris Smith in this post describe four very important of them, the "Four Horsemen of Catapocalypse":
- Failure — a function can result in an error due to lack of memory, an invalid human input, a network interruption etc.;
- Dependence — from one function call to the next one, as stateful operations;
- Uncertainty — different results from the same parameters;
- Destruction — actions that have permanent effects on the world, such as I/O.
We can find other monads in those languages to control State, Logging (the Writer monad), IO and others effects.
The metaphor of monads as containers/boxes becomes harder to fit when considering those examples. I think it brings a implicit notion of structure that kind of encompasses Arrays and Optionals very well, but needs to be stretched and revisited in order to hold the other ones.
Looking the examples and start from it seemed to me something that confuses the learner into building the concept (and even the purpose) of monads. On the other hand, it is very important to understand one of its major usages: define a common way to handle additional computations and side-effects in a uniform and controlled manner.
Purpose
I think it is important, before jump to the definitions and concepts, to say that the purpose of monads on the functional programming is to allow composing functions that have a return value type to another function that expect a different type as parameter. Nevertheless, it is not intended to match every return to any parameter type: monads work over some generic types returned by a function to compose them with functions that expect its associated type as a parameter (ex: to connect an Array<Int> returned by a function to function that expects an integer, like f(Int)).
Monads have several uses, but their general purpose (at least from a programming point of view) is to connect things.
Definitions
As examples just partially support the concept understanding, let's move to another approach: from the definition point of view on.
Monads, on programming language are generic types (e.g: Array<T>) what means it is associated to any type T (like Int, String etc.) or at least to a set of types with some constraints (like Dictionaries, that holds key-value pairs: they can hold any type as values, but keys are constrained to types that conforms to the Hashable protocol).
Besides being a generic type, monads should implement two functionalities:
- An unit function — a type constructor for the monad type M that receives a value from the associated type a and turn it into the generic type with a minimum context M(a) — What "being in the minimum context" means depends on the type itself. For an array, receiving a value, like the integer 1, it should be creating an integer array with just one element [1]; for an optional, receiving a string "Hello!" should be creating an Optional<String> with value .some("Hello!"). This could be extended to any other monad type.
- A flat map function — this function is a high-order function (meaning: it receives another function as a parameter) implemented for every instance of the monad M with associated type a. It receives as a parameter a function that converts a value of type a to another monad of the same type M, but that can have another associated type b. The flat map function shall return a monad of type M(b). We can define this function as M(a).flatMap(a → M(b)) → M(b) or flatMap(M(a), a → M(b)) → M(b) (choose the one that is clearer to you). The flat map function is also called bind function in some programming languages (such as Haskell).
The definition is, as discussed before, simple (not a complex one), but not bring much more information to understand monads.
As the next step I'll try is use a more "formal" definition of monads:
"Monads are monoids in the category of endofunctors".
What?!!?!?! 😮😧😱
As akward as it can be, this definition was fundamental to help me understand the concept. So, my next posts will break down the concepts present on this obscure definition and try to show how they are used, whenever possible, within our code. They will not be precise, mathematically speaking (as I lack the background to do so and maybe for us developers it would not add much support), but I hope they at least take you a step further on understanding monads from a programming point of view.
Let's start with the category part of “Monads are monoids in the category of endofunctors”.
Note: If you want to navigate to a specific post, here is a list of all monad related ones.