Monads are monoids in the category of endofunctors - a #Scala 3 journey, tweet-size, no psychobabble

Read on 👇
You'll need to know some abstract Scala and heard about:
- type lambdas
- functors
- monoids
- monads

at least in the practical sense that I talk about on the blog and YouTube channel. If you haven't, go to the blog/channel and run a quick search. I have them all.
Step 1 - monoids

Monoids are glorified combine functions with some properties. You've seen this in Cats.

Monoid reading here:

blog.rockthejvm.com/semigroups-and…
Step 2.

The thing is, this concept of "combining" can be generalized. The monoid above is equivalent to this other (stranger) form.

Notice that the API is returning functions instead of values.
These monoids are equivalent.
Why did I do that?

This (stranger) form can be further generalized:
- the Unit can be abstracted to some type U
- the tuple can be abstracted to some type P (for "product")
Now, notice that the methods return functions, which are the same as Function1 instances. We can generalize even the function concept:
This little monster is a representation of a "monoid in a monoidal category", or "monoid in the category of T", for short.

The monoid we know from Cats can easily derive from the general monster:
That monster can be taken one level up (or down?) by making it higher-kinded. Nothing else changed otherwise:
Step 3 - functors

Functors describe "mappable" things. You may know it from Cats. I talk about them in the practical #Scala sense on the blog and YouTube.

blog.rockthejvm.com/what-the-funct…
These functors have some properties (going to skip them).

Functors operate _between_ categories. In our case (puny Scala programmers), functors map to and from the _same_ category (Scala types).

In math jargon, those are called endofunctors. We have them here for free.
So we have
- "monoids in the category of"
- "endofunctors"

We need to stick the words together.
Step 4.1.

As programmers, we naturally transform values through functions. But for functors?

Functors have this thing called "natural transformations". Notice the structure similarity.
Example of a functor natural transformation in real life: List.headOption.

Other examples: .toList, .toTry, .toEither, .toOption
Step 4.2.

Squint at this type until colors blend.
It's found in Cats all the time.
Step 4.3.

Just as we compose functions in the style of compose(f, g) = x => f(g(x)), we can also compose functors.

But for endofunctors, we only care about composing them with functors of the same type.

Remember that F[F[A]] thing.
Here's a recap of the types involved.

Notice that nothing means anything anymore. I feel ya.
Step 5.

I've conveniently laid out the pieces so you can plug them into the little monster's type signature. This is what we get:

(read about type lambdas here: blog.rockthejvm.com/scala-3-type-l…)
Breathe.
Once we fit the pieces together, the monoid's methods are:
Because nothing means anything anymore, let's get back to the surface and get some air.

Here's an implementation of this mega-monoid for lists (which are functors; we can write a given Functor[List]):
Notice a really weird use of "combine".

In our first monoid, "combine" meant putting two values through a function. But "combine" can also mean
- parallelizing two futures
- cross-product of two sets
- flattening lists two levels deep (picture)

The whole damn concept changed.
The thing is, this general combine method is too general because it can mean anything and take any shape. So we came up with a much more useful primary API:
In other words, if you can define that kind of monoid, you've just written a monad.
Step 6.

But wait, that's not all. You can also go backwards. Let me write a monad trait in the style of Cats.
But if I can do that, then I can write the following methods for free:
I can also safely replace "extends Functor" with the type constraint (it "is" a functor), but kept it here for clarity.

So in reality, a Monad doesn't just extend Functor, but it also extends something more.
In other words, if you can write a monad, then you've just written a monoid in the category of (endo)functors.
Step 7.

Monads are not "just" monoids in the category of endofunctors, they are exactly monoids in the category of endofunctors.
You rock.

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Rock the JVM

Rock the JVM Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!

Follow Us on Twitter!