<img height="1" width="1" src="https://www.facebook.com/tr?id=1076094119157733&amp;ev=PageView &amp;noscript=1">

Those fancy words used by functional programmers purists really annoy me. Monads, Functors... Nonsense!!!

Posted by Javier Salcedo. Z on Tue, Jan 16, 2018

 

alt text

 Estimated reading time: 14 minutes

 

We, developers, hate and love things continually. We start to take great pleasure using those things that make the "aha!" in our heads quickly. e.g. patterns, libraries and language features. But those we do not follow swiftly we discard them and sometimes hate them. The same happens with sophisticated terms which some functional hippie guys try to sell us in places like conferences or meetups, terms that seem to come from The Lord of the Rings.

We are developers, we speak semicolons and curly braces right? So why should these words matter? If you are involved with the Scala world maybe you already have heard concepts like Monad, Functor and many others coming from mathematics.

For the next few minutes, let’s discuss why I think it is important to know a quite bit about the ideas behind these notions. We are going to tackle Monad, Functor, Natural Transformation and we will see how they are related to for comprehension and composition in Scala boundaries.

This article will not be another Monad tutorial or Monad introduction due to my very limited knowledge on this and because there are already so many other articles about it that could make more justice to explaining Monad. Certainly, it is possible to write code not knowing about dark, antique math fundamentals. We have been doing it like this for many years.

So of course Scala language is not an exception, you can write code as traditionally as it has been done for decades.

With Scala you can gain huge benefits like conciseness and maintainability writing imperative code style, you just need follow OOP principles and follow best practices and naming conventions. You can write less verbose code than Java at least.

However, if your daily job uses Scala you probably prefer functional style, and who doesn't? We enjoy avoiding mutations, doing recursion and using Scala collections to do things like:

Since Scala obstruct deals directly with null values it provides to us utilities to deal with values which might not exist, one of them is Option for example which possesses a repertoire of gadgets similar to the collections, like:

In both examples above there is an obvious common pattern that we see very often in our Scala code.

The mapfunction and flatMap that we heavily used in List, Seq or in other parametric types like Option, Try, Either or Future, are there because all these type constructors are Monads and Functors.

Note: we are going to use type constructor and parametric type to refer to the same concept. An Option[T] is a type constructor because it itself is not a type, we need to pass it a concrete type to create the final type e.g String to create an Option[String].

Let's define what a Monad is and, as I said above, this would not be a Monad tutorial. I will neither give you a very strict definition nor repeat what other Monad articles say such as "Monads are just chicken burritos o chicken wraps where the chicken is the type parameter". No. I just want to give a definition that suffices our Scala context and not one that would provoke a heart attack to some mathematicians who are already resting in their graves.

So we are going to say that a Monad M is a parametric type M[T] with two operations, flatMap and unit, that has to satisfy some laws.

In functional literature, flatMap is more commonly known as bind and has the following signature:

As Scala is both Functional and Object Oriented, the flatMap function is defined inside a trait or a class, so we can use the parameter m: M[T] in the implementation to refer to the instance itself which would be of type M[T].

On the other hand, unit is just a constructor function that goes from T to M[T] (or T => M[T]) in Scala each Monad has different names for it unit operation. e.g:

List is a Monad with unit(x) = List(x)

Set is a Monad with unit(x) = Set(x)

Option is a Monad with unit(x) = Some(x)

Now let's see Functors.

Functor F is a parametric type F[T] with a map operation. That has to satisfy some laws.

In other functional languages map usually has a signature like map(x: F[T], f: T => U): F[U] but again the fact that Scala is OO and map operation always is defined on Functor itself we omit x: F[T] and use this in the body of the operation. Some Functors in Scala.

List is a Functor with map(f: T => U):List[U] = List("1").map(e => e.toInt)

Set is a Functor with map(f: T => U):Set[U] = Set(2).map(_ + 2)

Option is a Functor with map(f: T => U):Option[U] = Option(true).map(_.toString).map(_.toUpperCase)

In both definitions I mention laws, Monad laws and Functors laws. I think it's not necessary to talk about those laws because: first, I don't want us to get bored; and second, as I said we don't need a rigid definition for our (Scala) interests.

So what are Monads good for? Despite of what we usually believe, Monad is not about side effect or values that can be absent or values that will be available at some point the time. No, Monads are about composition-- just simple composition! For that reason its main operation (flatMap) is also known as bind, as I said before.

I once read that Monads were like semicolons in programming languages, we use them not just to delimit lines but to compose sentences sequentially.

With Monad we compose expressions that are passing their result downstream while we manipulate them in an harmonic way.

Scala has a built-in feature that is dedicated entirely to Monads. That is for-comprehension. Scala's for/yield is more related with Haskell's do/return than Java's for-each. Regardless of what we tend to think for/yield has nothing to do with collections but with Monad.

This is the same example of the top re-written using for/yield obtaining the same result.

for/yield can be thought as tweezers and magnifying glassess that allow us to look inside Monads, pick-up the contained value, transform it and drop it back to another Monad.

We can use for/yield for any Monad/Functor parametric type, in other words any type that has flatMap,map and unit operations will be available for us to use it with for-comprehension.

There is no need for it to be a type constructor coming in the Standard Library. We can use it with custom types created from scratch.

Let's see a runnable exercise in the Scala Repl.

We are going to define a case class with the two operations flatMap and map inside it. Remember that case classes provide us an implicit apply constructor function, so that would be the unit operation.

We can see how our GateToWorld type works with for-comprehension doing this simple composition

Compiler will look at flatMap/map to extract values from objects one, two, three in the for block and it will figure out the unit function to use it in the yield block to construct a new Monad value with 6 in it. (GateToWorld.apply or new GateToWorld would be unit)

The idea with Monad patterns is to try to assemble all our programs to avoid the need to deal with the contained value. For that reason, getters functions in Monad have scary names like unsafePerformIO, or other simples names that somehow using also terrifies us because we know they are the devil and can break our programs entirely, like get from Option or head from List.

Let's do another exercise using our same custom useless Monad GateToWorld. The idea would be a tiny program with Inputs and Outputs to show how Monad fit in the entirely flow. So before we are going to refactor our Monad a bit to hide the contained value and define a getter method with an scary name to send a warning to whomever wants to access the value using it.

Now let's define a data model and some operations for our business.

We are going to compose a program which will ask for data to the employee, will do some stupid data transformation (normalizeEmployee) and will "save" that data in the "database" (faking it obviously)

Now let's run the program

As we could see for-comprehension and Monads (any parametric type withflatMap/map/unit operations) will give us, in my opinion, a wonderful way to deal with composition.

However, composition in Monad is restricted to each Monad type constructor, that means that we can not do something like:

Therefore we can't also do

That is because flatMap in List, for example, is defined to be something like

Where f parameter needs to be a function from A to List[B] or any subtype of GenTraversableOnce[B] (which is a supertype of List) so type system will complain if we try to put something like a function that goes from A to Either[B] that is the case of Right.apply (one of the unit operations for Either).

Of course saying of above we can resolve this very simple

But we are going to complicate it a bit and introduce another fancy term. We said that Either[_] and List[_]/ Seq[_] are Functors and Monads. So operations that go from one Functor to another Functor are called Natural Transformation. Exactly like toSeq that we just used to convert Either[_,Int] Functor to Seq[Int]/List[Int]Functor above.

a natural transformation provides a way of transforming one functor into another while respecting the internal structure. Wikipedia

Scala Standard Library's Functors already come with some Natural Transformation like toOption, toEither, toLeft, toRight, toTry.

While we usually represent functions like this f: A -> B, g: B -> C in the functional and mathematical literature. A Natural Transformation is represented with a curly arrow as follows f: A ~> B, g: B ~> C just to denote that A,B and C are functors,(A[_], B[_], C[_]).

For that reason, and the fact that Scala type system is crazy (in a good sense) and powerful, we might have seen in libraries like Scalaz and Cats, this curly arrow and others funny operators.

We will borrow a fragment of Scalaz Natural Transformation implementation just to see how they squeeze Scala type system to allow operators look like in the mathematical literature.

Scalaz Natural Transformation

As you can see they definitely complicate it. You will find many operations that already exist in the Scala Standard Library shown in these other libraries, Scalaz and Cats, in a different way. Another example is Monad's flatMap/bindthat we talked above, you might find it with the alias def >>=[B](f: A => M[B]):M[B] = flatMap(f).

I must confess although I am quite a fan of those awkwards operators, they don't help in an early research of these concepts.

So get back to Natural Transformation, the simple one, what is it good for?

Natural Transformation in addition with flatMap can be very useful to flatten types.

How many of us have found ourselves struggling when using an API that returns something like:

When we just need a simpleList[Employee], we usually resolve it with a lot of boilerplate code, with a lot of overusing pattern matching and with a lot of tedium.

But let see another way to deal with these nested types, flattening them, with flatMap and Natural Transformation.

We said that what we just need a List of Employees, but don't forget that there can be exceptions also in that return type, so ideally we should log them somehow.

First let's stay with a List of Employee

Now let's go for the errors

There are better approaches than this, of course, like groupBy for example. I just wanted an use case to flatten.

The process of flatten can be thought of in two steps: first, we need to transform all inner parametric types to the most outer (in this case to List[]) later we need to apply flatMap from the outer to the most inner (in this case the Option[]).

Of course there are many other scenarios where Natural Transformation makes sense.

To conclude we had mentioned terms like Monad, Functors and we saw how they are intrinsically related with some implementation of Scala features.

We looked at how for-comprehension,Monad, Functor and Natural Transformation are means of composition.

The way that typically these concepts are presented or explained is not the most pragmatic way, perhaps for that reason I used to be identified with this title a few years ago. Although we can not deny it now, these terms are being used out there, we can see how many libraries are based in these foundations; even Java 8 and TypeScript/Javascript have monadically type structures with filter, map and flatMap in their core (Optional, Stream in Java and Array in Javascript) so there should not be anything wrong in knowing where they come from.

I consider that studying and knowing about these ideas share the same importance as studying OOP patterns from books like e.g Gang of Four Design Patterns.

So don't be shy to say Category theory outloud and don't be mad if you listen to it.

The worst that could happen is that this guy appears if you say it three times.

 

alt text

 

And how cool would be that.

Resources

Recent Posts

Posts by Topic

see all

Subscribe to Email Updates