This post will cover the basic usage of an Applicative. We will also create our own data type and turn it into an Applicative.
First a caveat: I’m not a seasoned Scalaz developer with years and years of experience. This post represents my current understanding of the topic. Feel free to drop me a mail if you have suggestions for improvements so I can learn more!
The code examples are available at github.
So, what’s an Applicative
? This is the definition on wikipedia (ref1):
In functional programming, an applicative functor is a structure intermediate between functors and monads, in that they allow sequencing of functorial computations (unlike plain functors) but without deciding on which computation to perform on the basis of the result of a previous computation (unlike monads).
The definition of Functor
on wikipedia is (ref2):
In functional programming, a functor is a design pattern inspired by the definition from category theory, that allows for a generic type to apply a function inside without changing the structure of the generic type.
Ok, so what does that mean? Let’s be concrete and look at an example of a Functor
:
The generic type in the case is Option
, the function to apply inside is addOne
and the structure after we have invoked map
is the same as before we called the function. We can say that map
lifts addOne
(that has no knowledge of Option
) so that we can execute it inside the generic type Option
.
Scalaz provides a lift
function that is implemented like this:
And is used like so:
This is all very nice and we use Functor
everyday to map List’s, Option’s, Set’s etc, maybe without even thinking about that we are using it.
Useful as it is the Functor
get’s into trouble if we would like to lift a function that takes two arguments:
The attempt above doesn’t produce the result that we would like: Some(3)
but instead gives back a nested structure of Options
’s. The Functor
is not powerful enough to help us here!
One way to fix this is to use Option
as a Monad
which gives us access to flatMap
:
But as we will find out later in the post, it is not always preferable to go the whole way to a Monad
. Enter Applicative
.
From the definition above we know that an Applicative
is more then a Functor
but less then a Monad
. Will it give us enough power to solve the problem above?
If we look at Scalaz implementation of Applicative we can find a signature that looks promising:
We can use the function like so:
Scalaz provides us with an Applicative[Option]
, on it there is a function called apply2
that gives us just enough power to solve our problem.
And that’s :
Scalaz provides Applicative
’s for many common data types, like List
and Option
. Later in the post we will create an Applicative
for a data type the we have created our self.
But first we will investigate different functions that are defined on Applicative
.
First let’s look on alternative syntax for apply2
:
This syntax scales nicely:
Another useful operator is sequence
:
As we can see from the signature it takes as input a traversable data type that contains an Applicative
and turn it inside out.
Example of usage where the traversable is a List
and the Applicative
is an Option
:
Here’s another example where we use sequence
to wait until all Futures
has completed:
Let’s look at a similar operator called traverse
:
Example of usage:
We can compose Applicatives
like this:
We can also get the product of two Applicatives
:
I think I finish here because this is starting to get a a bit boring but I have added some more examples of different operators at github.
But what if we creates our own data type, can I get an Applicative
for that one as well?
So let’s do it!
I will use the classic validation example since it highlights why it is sometimes better to use an Applicative
then a Monad
in a nice way.
Ok, so let’s say that we have created or own Validator
If we would use the Validator
as a Monad
the client would use it like this:
It get’s the work done but it’s kind of half baked. If we look at the the result from the validation we see that we only reported that the name was invalid, in this case both the name and the age was wrong.
Why is that? Let’s look at how we implemented the Monad
for Validator
As you can see we have no option but to follow bind
’s (also known as flatMap
) short circuit behaviour when a failure occur (i.e. when something is Invalid). If the result from the previous computation was invalid we have no way to somehow merge failures or to continue the computation.
We can also see that the happy path is a chain of calculations, we first checks if the first validation was “Valid” we then proceed with the next validation and so on.
In this case we really don’t need all the power that a Monad
is giving us (even if it’s tempting).
And why don’t we need the power? Well if we look at our validation functions:
We can see that neither of the functions depends on any computations that we have done before it was invoked. Instead all our computations are isolated i.e. they don’t need any input from the previous calculation step. We could in fact run them in parallel if we wanted.
So the very thing that makes the Monad
powerful (the chaining of computations and short circuit behaviour) is to our disadvantage in this use case.
So like when Galadriel rejected the one ring, let’s settle for less power and use an Applicative
instead (but with less drama).
‘And now at last it comes. You will give me the Ring freely! In place of the Dark Lord you will set up a Queen. And I shall not be dark, but beautiful and terrible as the Morning and the Night! Fair as the Sea and the Sun and the Snow upon the Mountain! Dreadful as the Storm and the Lightning! Stronger than the foundations of the earth. All shall love me and despair!’
She lifted up her hand and from the ring that she wore there issued a great light that illuminated her alone and left all else dark. She stood before Frodo seeming now tall beyond measurement, and beautiful beyond enduring, terrible and worshipful. Then she let her hand fall, and the light faded, and suddenly she laughed again, and lo! she was shrunken: a slender elf-woman, clad in simple white, whose gentle voice was soft and sad.
I pass the test,’ she said. ‘I will diminish, and go into the West and remain Galadriel.’
First we look at how the client would use it:
Success! Or yeah, well maybe failure, but still! Success! Both errors are reported!
Here is the code for the Applicative[Validator]
As we can see, we now have the possibility to merge the errors so that all our shortcomings can be exposed. Also we don’t have the short circuit behaviour, all the validation functions get’s a chance to run. All is good!
So to sum up, sometimes it’s better to use an Applicative
then a Monad
even if it’s less powerful.
If we want all our calculations to run even if some fails then we should use an Applicative
instead of a Monad
.
If we use the Scalaz library it’s pretty easy to create our own Monads
and Applicatives
, as a by-product we also get access to all those nifty little operators that the people behinde Scalaz has implemented over the years!
The code examples are available at github.