Continue

We are almost there! Let’s tackle Applicative now. What can we do if not only are data is encapsulated in some structure, but even our function which we want to apply to?

Can we apply a list of functions over a list of values? Or an Optional/Result function over an Optional/Result value? Does it even make sense?

Let’s define Applicative as being a Functor that has a `pure` function similar to our Monoid, as well as a `sequentialApplication` one that we will shorten as the cryptix <>. Since it is a Functor, remember that it also has a map function available.

The pure function simply encapsulates a type inside itself. For example, a list constructor is precisely that, like python’s list(2, 3) creating a new list. The <> is a bit more complex, it takes as parameter a function that is encapsulated in this very type and operates on type A. Its second parameter is an encapsulated object containing type A. And the important thing comes here: it will apply the encapsulated function to an encapsulated data, without unwrapping first.

Let’s say, I have a text field where the user Maybe entered his/her name (sorry) and a field where we await an age. We’ll store these inside a Result<String> and a Result<Age> type.

Let’s say we have a User constructor that awaits a name and an age. We could handle each parameter separately here, but what if we have 20? So we instead do something like pure(createUser) <> nameResult <> ageResult. This magic line will apply the Just createUser function (that is, wrapped into a Result with an existing value due to pure) to a possibly missing name. Let’s stop for a moment here and talk about currying. In many FP languages, calling a function with less parameters is not a compile time error. It gives back a new function that awaits one less parameter. Eg `+ 3` is a lambda that got its first parameter as 3, and will “execute” when we give it the second parameter.

Knowing this, our evaluation so far will be something like Just (createUser(nameResult if it has a value)) or Nothing. Now we apply this, yet again enwrapped function to the last parameter, so we will get as a resulting type a Result<User>, which will contain a user when both values were sent, and will be Nothing if any of them were absent - cool isn’t it?

But I know, we are here for Monads!

Well, Monads are just monoids in the category of endofunctors. Just kidding. They are Applicatices, that also have a `bind` method.

So you’ve seen how we could “sequentially apply” functions. But the “problem” with Applicatives, is that we can’t depend on the output of a previous function — in the previous example we could not have ageResult’s evaluation change depending on what was returned previously. Let’s see another Applicative, the often misunderstood IO.

putStrLn has the following type: String -> IO ().

That is, it waits a string and gives back an IO structure that returns void (actually it is called Unit). If we were to somehow execute it, it would print that string ending with a newline. If we do

(x => putStrLn(“world”)) <*> putStrLn(“hello”), it will output (if we know how to execute it) hello world in two lines. The reason for this strange ordering is, that we apply a function that drops its first parameter to the second one. (Haskell does have a shorthand for this!)

But how can I act upon the result of a previous computation in a “sequential application”, eg. read in a line and print hello $name? By `bind`! It does the following: it needs a monad at hand, with encapsulated type A (eg. IO String for the readline we will use), a function that takes that type A (String) and returns this monad with any type (we will print out the string so we will use putStrLn)

So, bind(getline, name => putStrLn(“hello $name”)) will do what we want and you have just used your first proper Monad (Haskell of course provides a nice syntactic sugar over this called do notations)

With these abstract structures, IO can be dynamically constructed and side effects will only happen where we expect them.