Const and Identity Monads
Unexpectedly Useful Constructs
Today I’m going to talk about my two favorite Monads — Identity and Const. These are basic Unit Monads, holding just a value. They’re probably the simplest Monads to understand, but they have powerful implications and uses. If you don’t know about Monads already, check out my simple explanation of the Monad as an interface here.
Let’s first talk about the Identity Monad. The Identity Monad is constructed by sinking a simple value into it, be it a number, string, or object. It doesn’t do anything special to that value, it just puts it in our nice fancy monadic box, from which point we can map over the contents, chain the contents into a new monadic type, or unwrap the box to find out what our resulting value is. We can define it simply, like so (I like to hide my Monads’ contents in a Symbol Key):
So we adhere to our Monad Interface by defining map, chain, and unwrap methods. We use our secret value to implement those methods. As you can see, Identity is just a wrapper for the secret value, and doesn’t do anything else special. Note how we define unwrap. We chain the
identity function. The identity function is the sister function to the Identity monad — it returns whatever you put into it. Since chain calls its supplied function
f on the secret value of the Identity instance, it will effectively just return that secret value. This can be applied on any Monad to implement unwrap. It’s part of the mathematically symmetrical nature of Monads that we get the free definition of unwrap via our chain definition. It works the other way too, (thus the symmetry). We could’ve defined chain by reusing definitions from map and unwrap, like so:
As you can see, mapping over the Identity instance and then unwrapping its contents is essentially the exact same result as applying
f to the unwrapped value. This makes the Identity Monad perfect for illustrating the mathematical symmetry of Monads. All Monads should be capable of interchanging the definitions of chain or unwrap by using one another combined with map. This nifty interchangeability is essentially what makes a Monad a Monad!
So now that we know all about Identity, let’s move on to the Const Monad. Const is really a lot like Identity, except whatever you sink into the Const monad is unchangeable. You can map over it as much as you like, but the result will always be exactly what you put into it originally. We can define it as such:
As you can see, mapping the Const Monad always produces itself, with no modification, as does chaining it. The truth behind this is that it’s technically not a Monad on its own. But if you look at the Either Monad’s Left portion, you’ll notice it looks exactly like Const — that’s because it is Const!
So what good is this? Let’s write a little example to illustrate one simple use — functional getters and setters. This is sort of an example of ‘Lenses’, but vastly simplified. A Lens is a function that can behave as both a getter and a setter by hijacking the Identity and Const constructs. I however will simply be illustrating how we can either prevent or allow the setting of an object’s properties by using either Const or Identity. First of all, if you’re following along using codepen or your own IDE, copy the definition of curry that I’ll provide:
If you don’t already know, curry is a way to provide a function with fewer than its total required parameters to create something called a partial application. People generally refer to the process of partial application as currying. Its a staple of functional programming. I’ll write more about curry another time, for now that’s all you need to continue this example.
Now lets define some pointfree-style get and set functions:
We curry some functions that look at an
obj which we assume is a Monad with
map. We then transform the underlying value using
set, or return the requested property with
get. Currying them allows us to do such functional wizardry as this:
get function allows us to pre-load a parameter, returning a function that takes the remaining parameters. Cool! Moving on to some usage:
I’ve defined myself here as an example. We copy the
me object using the
... spread syntax, because otherwise we will have a reference to the original
me object, causing both our Const and Identity instances to point to that original, which is not the behavior we want. So what do you think will happen when we try to set the Const’s and the Identity’s inner values, respectively?
If you guessed that we would not be able to modify Const, but we would be able to modify Identity, you’d be correct! If you keep following along with Monads, you’ll come to understand that Identity and Const are just building blocks for other Monads and functional operations. Here’s a pen to show my work:
Hope you enjoyed another Functional Programming adventure. Stay tuned for more, and FP on!