A monad is a monoid in the category of endofunctors. Whats the problem? #SoMe2

preview_player
Показать описание
You may have heard that a monad is a monoid in the category of endofunctors, but what does that actually mean? In this video, you'll learn the basics of category theory and understand the infamous sentence!

This is my entry to the summer of math exposition round 2 hosted by @3blue1brown.
Рекомендации по теме
Комментарии
Автор

Other than audio (unless you have any specific tips), what can I do to make my future videos better? Any feedback (even negative) is strongly appreciated!

AByteofCode
Автор

This is probably the clearest explanation of a monad I've seen yet. I still don't understand it at all, but it's a really good explanation.

SkyyySi
Автор

Once you've spent years on wiping every last bit of state from the inherently stateful computer system, developing a perfectly stateless functional language, the monad is a method to remedy your colossal mistake and re-introduce state into your language, except more awkwardly.

sharpfang
Автор

"A Monad is a Monoid in the category of endofunctors. No one actually knows what that means, they'll just parrot "A Monad is a Monoid in the category of endofunctors" at you repeatedly to make themselves look smart" -The guy that did a 9 minute ur mom joke using category theory

randomperson
Автор

Monad: I am a monoid in the category of endofunctors.
Me: I don't even know who you are.

pro
Автор

Well, that was the most informed 4 minutes I've wasted in my entire career of coding. I didn't regret.

izaquieluiz
Автор

I got the math part — really well explained, thank you — but didn't get the coding part.

I feel like instead of just saying "...and this Box type is a functor", you could have said "..and this Box type is a functor, since [explanation of how it maps objects and morphisms in one category to objects and morphisms in another]". From that point on, I was lost.

tiagomacedo
Автор

what does "a coconut is just a nut" mean in category theory?

NICK....
Автор

Me after watching the eightth "intuitive introduction" to a complicated topic, and still not understanding anything about it: 🗿

thatkindcoder
Автор

It's useful to know the terms, but I feel like it would more helpful to see a code example with real-world uses, like Errors and Option types.

LowestofheDead
Автор

I no longer understand what a monad is.

christiansheridan
Автор

Great, short explainer for categories, monoids, etc. But the operation you compose for the Box example (3:57) doesn't have anything to do with monads. Composing "map" as you show there with a.map(b).map(c) or a.map(b.map(c)) is just composition of morphisms in the functor and works for all functors.

What makes a functor a monad is the *identity* operation (which you correctly write out in 4:00 as x => Box(x)) and a way of composing the functor itself: e.g. being able to turn a Box(Box(x)) into a Box(x). This latter operation is what you're missing; you can think if it as a generic "flatten" operation. Lists are a monad because you can turn any object into a list of just that object (x => [x]) and you can turn a list of lists into a flat list:

def flatten(outer: List[List[T]]) -> List[T]:
if len(outer) == 0:
return []
return [outer[0]] + flatten(outer[1:])

... or with the Box monad:

def flatten(outer: Box[Box[T]]) -> Box[T]:
return Box(outer.value.value)

This "flatten" is the associative operation that makes things like Box, List, etc into monads. The function x => Box(x) is a functor that maps every type X in the category of the program's types into the type Box[X]. But there are other functions that take some type A and map it to Box[B]. To compose these in a way that satisfies the associativity laws, you need a way to take a -> Box[b] and b -> Box[c] and get a -> Box[c]. This is done through the "bind" operation in a monad, but the secret sauce is that you can write the bind operation as:

def bind(box: Box[A], f: A => Box[B]) -> Box[B]:
return flatten(box.map(f))

To walk this through, the function f takes an A and returns a Box[B]. When you use that in box.map(f), the map function takes the Box[A], and gives the A inside the Box to the function f, which returns a Box[B]. But the way map() is defined, it puts whatever its argument returned into another Box! So the result of box.map(f) is a Box[Box[B]]. That's why we call flatten() on the result, to turn it into just a Box[B].

When we say there's a monoid defined on these endofunctors, on functions that take an instance of some type A and output a Box of some type B, we give the identity function as x => Box(x), which doesn't alter its argument except for putting it in a Box, and give the way of composing other functions of the form (A -> Box[B]) -> (B -> Box[C]) -> (A -> Box[C]), which we can do by composing map() calls as long as we flatten() the results before shimmying them along. This is why what Haskell calls the "bind" operation (spelled as the infix operator >>=) is called flatMap() in a lot of other languages and libraries: it's doing a map(), followed by a flatten(), and this combined operation gives you the means to compose functions with type signatures that look like A -> Box[B] and B -> Box[C]:

= Box(a).flatMap(a -> a2BoxB(a).flatMap(b2BoxC))

The reason x => Box(x) is the identity in this monoid is that you can put this function in a flatMap() anywhere and it won't change the Box that you're flatMap()-ing:

Box(a).flatMap(x => Box(x)) = Box(a)

CPOtheDragonSlayer
Автор

For anyone still confused but almost there: watch the first monad video again. it makes perfect sense now. i understand everything now and my brain hurts from being so massive and huge now

badmanjones
Автор

I think what this is missing is multiple examples, because what's most amazing about programming with monads is making code that can operate on any monad, when a monad means something totally different for different implementations. A "Box monad" is a lot like an "Option monad", but not very similar to a "List monad", or any other random thing. So then you can write code generic over monads and it will do something totally different depending on what implementation you give it

AndrewBrownK
Автор

Honestly I think videos like this are more likely to contribute to continued skepticism of functional programming instead of winning anyone over.

sfulibarri
Автор

I think at 3:19 not the category is called a Monad but monoids inside this category.
You are right, that if you look at this category and take the identity object and the product, this forms a Monoid in the algebraic sense, but a categoricaly defined monoid here works a bit differend.
You need the product and Id object you mentioned, not to make the category a monoid but to be able to define monoids inside of the category.
A monoid is an object m with a morphism from (m x m) to m and one from Id to m. This object then is a Monad. Its an endofunctor with this additional structure in form of those two morphisms (which also have to follow some associativity rules). In Functional Programming the morphism (m x m)->m is often called "flatten" and the morphism Id->m often "return" or "pure"

stames
Автор

You lost me in the first 3 seconds but pulled me back for most of the video, only to lose me again in the last minute

Great explanation, 10/10

Dango
Автор

I think the biggest hurdle to really understand monads is that their definition is part of theories that we, as developers, don't give a single flying f*ck about 😅

But to finally being able to conclude this is a relief. Thank you for this awesome video.

Brunoenribeiro
Автор

I think much of the confusion is because you can't implement a monad (like you would implement an interface), you can only create a type which forms a monad(under a specific explicit or implicit trait system), in likely an incomparable way with how others implement theirs (in naming, order, synchronicity, operators vs methods vs free functions, etc, some with weak trait enforcement contacts(eg javascript or typescript), some strong(eg haskell), Some using functions with two arguments, others using functions that return another function, a=> b => op(a)(b) or (a, b) => op(a, b).

a_name
Автор

this explanation is amazingly smoothly done

Miranda-ycll