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!
This is literally the best video I've seen what a monad is. Good job! I always forgot what endofunctors were when thinking about monads, but your description of the "category of endofunctors" being all the possible mappings to itself of another category is simple and easy to understand. Edit: i think it would have been even better if you added one other code example of a more complicated monad (like Maybe or List)
@@zyansheep Thanks my man! About the edit, you're right I should have added an example of a monad with actual extra logic, but last time I used an example for a monad, that was the only thing a lot of people got out of it, so thought I would better avoid that :/
subtitles. NOT hard-subbed (= rendered onto the video), but soft-subbed using youtube's subtitle functionality. simply copy-paste your script. the auto-generated subs aren't always perfect, and especially in a video like this, where every word is chosen carefully, i don't wanna trust a speech-to-text algorithm
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.
@@scoreunder All of them are variants of state. List and Log monads are an append-only storage, so a log of states, be it meta- (log) or data- (list) oriented. Promise and Await are encoding execution queue capable of wait states into a finite state machine. Maybe is a 'machine has entered invalid state' state.
@@kittysplode The state was already there, natively. It's still out there, truly reflecting the entire state of the program. It must be there for the CPU to work. And you cobble a replacement substitute together on your own, and haul it around everywhere you need it alongside arguments and return values, while the real thing is already everywhere you might need it, except walled away.
"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
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.
Indeed. The moment Box(result) becomes self+result I was lost too. But AFAIU monads in Haskell could be expressed in usual programming terms as 'hiding' in such Boxes some useful payload (with original value) to get extended 'laterial' functionality. And you can put such Boxes to functions which works with original values as expected - and this is all these 'monoids and identity' gibberish are about. If you had function of value sum(value,value) you could call Box sum(Box, Box) and get expected result with some laterial additional computations inside Boxes (for example Box could count up how many additions happend with it's value before). This is why this 'map one category to another' is important in some way.
I admit the second part was rushed. I was about to leave for holidays and had to rush the ending to upload before the SoMe2 deadline. I'll try my best to not repeat that mistake.
The math word and the computer word are related but you can understand one without the other. If you understood the design pattern before but now don't, then ignore the last minute of this video which had a bit of unmarked pseudocode which is what I think may have confused you. If there's any conflicting info in your head rn, would you mind telling me what it is so I can clarify?
@@AByteofCode My view of monads exist in a narrow context. I know what they are from my experience with FP languages. Anything outside of that specific narrow context flies right over my head (especially category theory). It's not that your explanation is bad, it's just that... If someone doesn't have a mathematical background, like myself, it may be futile to explain monads to them in such a way.
@@christiansheridan3410 Hmm I tried making this explanation so that people without a math background would have a chance of understanding. I do see what you mean though
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
Although I agree, that wasn't in the scope of the video as it was more of a video about category theory, just I had to find some way to justify uploading it on a byte of *code*. I could make a video about the monad types though, with code examples and what problem each one solves.
@WaveHello notice, that what @A Byte of Code explain, requires you to use your brain effort to try and understand the concept. With examples, it would be easier to follow, but it would also be easier to come up with misconceptions, because your brain wouldn't be working as hard.
@@danielwilkowski5899 In my previous video, I used an example but a lot of people thought that example was the only thing you could do with monads. You hit the nail on the head here!
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(a2BoxB).flatMap(b2BoxC) = 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)
Great explanation! The associativity equality shown at the bottom is what I was going to put but thought it'd be too complicated as a thing to show on screen for a few seconds. Otherwise, the "+" "operator" shown in the code example was meant to encapsulate the idea of flattening but I'll admit I left out too many details in the code part :/
@@AByteofCode I saw that "+" operator and I wondered what the heck it was doing adding two boxes together. It would have been nice to have gotten an explanation.
Wow this helped me understand a lot more after watching the video. I have been working with flatMap and map in java/scala, and also trying to learn the core functional programming ideas. It's all starting to connect in my head thanks to this, so I really would like to say thank you!!! Are there any books on the subject you'd recommend?
@@hotharvey2 I recommend Bartosz Milewski's Category Theory for Programmers, which helped me understand the motivation for functional patterns and category theory in general.
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
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"
Agree. Let me rephrase to hopefully make it clearer. I am just a beginner in category theory. Corrections are welcome. The category of endofunctors forms a monoidal category. Functor composition acts as the total, associative operator ⊗. Identity functor acts as the identity object I. Inside a monoidal category, if an object M (here objects are endofunctors) equips with two morphisms μ: M ⊗ M → M and η: I → M, then we call it a monoid in this monoidal category. In particular, monoid objects in category of endofunctors are also called monad. Wiki has more precise definition for monoid: en.m.wikipedia.org/wiki/Monoid_(category_theory) I found Bartosz's lessons extremely useful for understanding category theory. Despite being theoretical, his presentation is programmer friendly. Highly suggest: ruclips.net/p/PLbgaMIhjbmEnaH_LTkxLI7FMa2HsnawM_
It is weird to put a precise mathematical name to my preferred pattern of programming. I always preferred monads over other type of functions such as functions that change given output parameters. Now I can sound very pedantic when talking about my program at work: "So the attribute function filter is a monad of the class. Any questions? Oh, of course, I will explain what a monad is. A monad of X is a monoid in the ..." My dream come true!
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).
Yes, it's pretty abstract when compared with the usual lessons on Objects and OOP (loosely: class is to an object, as a vehicle is to a car) Monads seem like more of a description of behaviour which is less tangible than object oriented stuff. I would like to point out also, that people tend to see functional programming as a wholly separate ideology and style to OOP, but in reality, if we can understand both and mix+match (e.g rust has great functional aspects) then we will hopefully all be better off.
You're absolutely right! Writing functional code in an OOP codebase is really powerful. Also yeah in general, FP is quite mathematical and not practical, which makes it overall confusing. Then you add vocabulary; a property in math is different to a property in programming, functors sound like functions but aren't, types are classes but not, etc...
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.
Thanks for covering morphisms, functors. Many people skip that bit. And yes, like others have pointed out, this is by far the crispest explanation. Few more points that would be good to know. 1. - Why is the identity needed to make a Monoid? - What goes wrong if we try to make Monad from a semigroup? and BTW is there a concept of `Group` also? 2. 'Category of endofunctors on a category' Won't that be the category of all morphisms? Or in other words, what is the difference between an endofunctor and a morphism? @AByteofCode
You kinda just have a table of properties and what you call a set with those properties, so as far as i know some nerd went "yeah monoid is a cool name for this" Also, Group does exist, its just Semigroup but you add Identity and Inverse (which is for each item x there is an item y for which x * y = the identity element). Otherwise, a morphism is an arrow between two objects, and an endofunctor is an arrow from a category to itself. You could say an endofunctor is a morphism from a category to itself (note the endo prefix) but there is a specific term for arrows between categories so we use that instead.
What you described at 2:41 and 3:14 were not monoids but monoidal categories. A monoid is an object A in a monoidal category (C,x) and a morphism AxA->A satisfying some identities. So at 3:14 you called (End(X), o) a monad, but really it's just a monoidal category. Monads are monoid objects in (End(X), o), that is, they are special endofunctors of X.
yeah this is one of those things which honestly has to be left out of the discussion because it makes it too long. In order to talk about monoidal categories you need to get a little bit into the weeds of their coherence conditions and possibly require an explanation of the tensor product. Both finite products and coproducts can form symmetric monoidal categories, but what that means really depends on how well you understand products and coproducts. Also there are more abstract definitions were monads are objects in bicategories, which is already losing the spirit of why most programmers care about monads. It's just too deep for most programmers to deal with at the start.
@@thestemgamer3346 They did talk about monoidal categories in the video, they just (incorrectly) called them monoids while doing so. They could have just mentioned that monoids are objects in the monoidal category they defined and glossed over the associativity and identity conditions given that they already talked about them for monoidal categories. This isn't a matter of which level of abstraction is relevant. They gave an incorrect definition of monads at the lowest level of abstraction. A monad is an endofunctor. I don't think incorrectly calling it the category of all endofunctors is more useful to programmers. Finally, this is a submission to SoME2 a mathematics exposition competition. Of course there should be some level of hand waving to appeal to a lay audience but the definitions should at least be correct, especially when that very definition is the thing being explained.
Yeah it's unfortunate that the original quote wasn't "in the monoidal category of endofunctors". Would've saved many man hours of incorrect explanations (and more hours of people listening to these explanations)
@@TacoDude314 oh I agree, anything incorrect should be called out. Especially when this topic pops up, in the context of computer programming, there are a lot of incorrect definitions. And if you want to treat the subject categorically, you can't really pull any punches. There are a few other issues with the video, for example, divisibility is not the same as division or inverses (mentioned 2:33). Also map wouldn't form a monoid, it is simply an endofunctor, you would need a different object which encapsulates the composition of multiple maps to be able to form a monoid. For example, people often confuse the monad object with the object itself. Which isn't really true. Are list's monads, or are they just types in which there exists a monad object which acts through the bind function? A lot of people assume that lists are monads and functors, because they take typeclasses to be like inheritance and so instancing a typeclass creates this "IS A" relationship in their minds. So a list "IS" a monad to them, when this is really not the case. Like you mentioned monads are just endofunctors, but it's more than that, they're the endofunctor created by the composition of adjunctions. The monad is just an object that captures that adjunction. How do you explain this to programmers? You don't, so you just don't mention it. I'm just mentioning that the level of detail required here is often not necessary when addressing this topic to programmers. So it's always going to result in some weird definitions and a lot of missing information. Taking criticism is also an important part of being a content creator too.
Great video. Small pedantic point on my end: at some point you kind of say that regular endomorphisms, unlike endofunctors, don't have an "observable effect" because they don't explicitly define a mapping of the internal structure of objects. This seems to kind of miss the paradigm shift of that makes category theory so powerful, where the observable effects we care about concern the external structure of morphisms, rather than the internal structure of objects. That is to say, the "observable effect" is "observable" in the sense that it interracts with other morphisms around it in a special way.
I've seen a bunch of explanations on what a monad is by this point, and this has to be by far the most understandable I've encountered at this point... thanks! I feel like I actually understand this definition properly now!
Associativity: exists IEEE floating point standard: And I took that personally (with floating point numbers A×B×C doesn't necessarily equal A×C×B due to rounding error, and that's also the reason -ffast-math option exists for many c++ compilers)
Given that everyone writes monads when they need them, but don't call them this way, I'm still unsure why we need to call them that way or explain them this way. "A monad is a function that wraps stuff to do (like type validation, error handling) around a value that may (for example) cause troubles if left unchecked. The monad will return the same inout value if it's valid, or a replacement of the desired type, so it's not even ALWAYS an identity." There.
It's a joke in a blog post called "a brief incomplete and mostly wrong history of programming". It's said by a Haskell programmer in response to "Haskell is too difficult to learn". The crux of the joke is that it's a mostly useless definition
There's a lot more things you can do with Monads than just error handling though. You can access an environment or modify a state, for example. In Haskell, the IO monad is the only way to perform side-effects.
So there is this thing called category theory and I'm trying to make sense of it. The tool I use to make sense of it is "understanding," which is a functor that returns an updated version of the thing I still call "me". Therefore, understanding is an endofunctor. If I understand endofunctors *then* understand monoids it's the same as understanding monoids and *then* understanding endofunctors. Therefore, understanding is a monoid within the category of me.
but to have a monad in computer science you need three different functions constructor, the map function, and the bind function The constructor creates instances of Foo The map function maps transformations of x -> y to Foo(x) -> Foo(y) The bind function maps transformations of x -> Foo(y) to Foo(x) -> Foo(y) The original paper about monads in computer science specifies you need all three in order to have any semblance of useful composition. In C#, "map" is called Select, and "bind" is SelectMany In JS, Rust, and Scala, "map" is map, and "bind" is flatMap in Haskell, "map" is map or fmap, and "bind" is >>=
You can construct fmap and join from return and bind. Using only the two methods return and bind was the original Haskell way of defining Monad, which for some reason was not a subclass of Functor. (Haskell also added a fail method, which has no counterpart in category theory and was arguably a design error, because not all monads necessarily have a way to represent failure; think for example of the Identity Monad)
Brilliant, i tried watching and reading tens of videos on category theory and couldnt understand anything due to crappy namings, but now i see it is more simple than those words. Thank you for this brillant video!
Yea, i agree, that's one of the best monad explanations available on youtube! I firstly thought it will be another "monad is just pattern", but it was clear and correct explaniation! Good Job! (sorrry for bad english)
Well I also happen to have a video about it being a pattern, just wanted to explain the deadly sentence as well :) Thank you very much, and don't worry about the english!
The most interesting things about monads is, i can do safe IO operation when wrapping IO operation inside "monad-like" types in imperative language, this also can make me write less boilerplate code for error checking.
Is it important for the function input type to match the function output type? I raised this question in SO and was told that every type belongs to the same category! So the function can take in an integer (a type) and return a string (also a type) - and nothing is violated. (Of course I am omitting the generics with templates here for simplicity).
A monad can be seen as a mapping between types, together a mapping between functions (between types). So given types X and Y, you'll get M[X] and M[Y], and given f : X → Y, you'll get M(f) : M[X] → M[Y]. And in addition you have M : X → M[X], and it all needs to fit together with the function chaining (M(f ° g) = M(f)°M(g), M(f(x)) = M(f)(M(x)), etc.) M[_] might be a generic type (that's the common case), or it might be a constant type, or some complicated type function.
The input and output types don't matter. The point of monads (or functors in general) is that the external type (the box) is what matters and stays the same, so usually, unless specific differently, the insides can change type.
The first part of the video was excellent, but when you started explaining the connection to programming, it would be great if you slowed down and showed the correspondence between terms in category theory and terms in programming
I can't believe I finally understand the shit! I've come across this years ago. I can't believe it had always been so simple. You've made me feel like a moron and a genius at the same time, congratulations
This is interesting and I think that it would make sense for you to go further on the topic please 🙏🏼 find out the time and the energy we all need to have more because it was just not enough 😅
3:35 - "this box right here" what exactly is this sentence referring to? the arrow points to `self.value` which is not a box (except for nested boxes, but that wasn't mentioned anywhere) 3:46 - what does it mean to add a box to another box ? the code shown here throws a type error (TypeError: unsupported operand type(s) for +: 'Box' and 'Box'). the following explanation "the rest of the method is simply combining two boxes in order to return one" doesnt explain *how* this combination works either 3:58 - the receiver of the latter `map` in the second line is a function instead of a box, which means its a completely different function that just happens to have the same name. how is this a valid comparison ? and why isn't this mentioned?
Well, what I can make out is that 'self.value' can be of any type, including but not necessarily a 'Box' object. And 'map' returns a 'Box' object of any value, from the existing instance of 'Box' class. So, you can pass 'map' method a theoretical 'function' argument that return a new 'Box' instance that has as its 'value' the original 'Box' the method instance belongs to. Resulting, in short, with a "NewBox.value == OldBox". So "OldBox.map(func).value = OldBox". And that's as far as I got. Because, when he makes the equality "a.map(b).map(c) = a.map(b.map(c))" the obvious problem here is that the 'map' method only takes another method. But 'b' is treated as both a method and a 'Box' class object which makes no sense and pretty much turns the last 30 seconds of the video into non-sense for me as well.
Oh god that CS part was scuffed lol. "this box right here" was meant to point at the class in general, and the + and associativity maps were pseudocode that I forgot to mention as such. I'm very sorry about all of that :|
@Nicholas Preda line 1: yes line 2: say the 'function' is a box factory, when called with the value of the previous box, you get a new box. I didn't explain how the combination worked because that is a per-implementation specific detail, and last time I mentionned implementation specifics people thought that was the only option :/ line 3: what I meant was that if we got rid of the "calling the function part" and just assumed that map just took boxes directly, then the map things work.
I am not a category theory specialist, but to make your explanation truly usefull, you should mention the flatMap, which allows to composite monads. As if you return a Promise from a Promise, it is still a Promise, this operation makes monad whatever the definition says.
I'll need a minute to take in everything that you present in this vid - but I think if I try I actually _will_ be able to understand it, since the explanation is clear. Thanks!
The first part was really intuitive, thanks for that. Up to the point, what it all ment. The last part was a bit on a rush. But I understand, that this video was ment to be a short introduction, so maybe that wasn‘t even your intention.
so what's the difference between a monoid in a category, compared to an ordinary abstract-algebra monoid? I assume it has to at least satisfy some additional coherence constraints? Being *in* a category, does that mean it's a special kind of object or a morphism or something different? Maybe it's a morphism mapping from products?
I think the biggest misstep in this otherwise flawless video is this: right at the end, you blaze through all that math you've carefully built up and just assert that it is what it is in code. It's not clear what makes map an endofunctor, what the category is (Box or the object it holds?), or why we can call that a category. The transformation undergone through that endofunctor is also vague. Oh, and on second thought, I'm docking 10 points for sticking an undefined and totally handwaved addition operation in there between a value of type Box and the value returned from func.
This video was awesome! And I love how straightforward the box type is 😁. Would have loved an extra 30 seconds showing how to use this in a productive way! Like, how this translates into an 'IOMonad'
Can you please elaborate more on functors, like how will it map morphisms and objects in two different categories? And what are these morphisms and objects that are being mapped in terms of programming... Plus, how do endofunctors map to themselves
Gotta remember that at its core, category theory is all about abstracting abstraction and that functors are purely theoretical ideas. The question of "how" as a generality thus doesn't make much sense. You can do whatever mappings you want however you want them. The only rules for you to be able to call them functors are that every single object & morphism from A must map to something in B (plus a consistency thing explained in the video). Take the category of positive numbers and the category of negative numbers (we'll define morphisms as being +1 or -1 depending on which ctgry). You can create a functor by mapping the number 1 to -1, number 2 to -2 and so on, then map the arrow "1 to 2" to "-1 to -2" and so on. This is just one example, you can make whatever objects you want (objects are generally data like numbers, strings, bools, custom classes, etc) and morphisms are just things you can do to a piece of data to make it another piece of data of the same type. An endofunctor just means you have the same category at the start and the end. For example one endofunctor on numbers could be "1 to 2" and "2 to 3" and so on with mapping the "1->2" arrow to the "2->3" arrow, etc. If I haven't answered your question in a satisfying way let me know!
Are there any specific topics you'd want talked about? Otherwise I do have long term plans for a series about abstract algebra which would certainly have an episode about categories
I am filled with regret for the day I became curious about what a Monad is after a computerphile video, so I searched for it, and now my feed is filled with Monad explainers that don't help me understand Monads. I've long since stopped caring, but keep being recommended more or less accurate-according-to-comments and jargon-heavy videos, this is my new hell. Thanks for trying, though.
That's a good question! I'd say that an endomorphism is given to a specific object, whereas an identity function applies to all objects, but as far as I know, the line is a bit blurry between the two words
Understanding the theory is honestly way better than people trying to jump straight into code. I've watched and read multiple posts/vids about monoids and this really helps fix up the gaps. Thanks!
I know that concepts click at different times for different people. Some may find this too advanced and some may find it too simplistic. But it was exactly at the conscise-but-precise level I needed to FINALLY feel for the first time like I understood the diabolic sentence! Now let's see how long that feeling lasts :). Thank you very much, great video!
This is close enough to get by, but there are some terminology mix-ups that might be confusing to some: You claim to have a category of endofunctors, but you really just have a bunch of endofunctors. Without the morphisms, it's not really clear what this category even is. In the case of the category of endofunctors, the morphisms are natural transformations. Once you give it the bifunctor (operator), it doesn't become a monoid itself, it becomes a monoidal category. A monoid is an object in that category along with a pair of morphisms that take elements from the respective product object and identity object into itself. Because the objects are endofunctors in X and the morphisms are natural transformations in X, that monoid object is called a monad in X. For a type constructor like Box to be a monad, it needs a few things: (1) a way to turn any object into a "wrapped" one, i.e. a constructor, (2) a way to turn any function between types into a function between "wrapped" types, i.e. a map implementation, and (3) a way to turn a "doubly wrapped" object into a "singly wrapped" one, i.e. a flatten implementation. You can get away with implementing just a flatmap to get (2) and (3) in one go, which is what you do here after supposing that f returns a Box type. You call "map" a monoid in the category of boxes, but a monoid is an object and the objects in our category are endofunctors, which "map" is not an example of. Instead, the type constructor Box, with the object constructor and the (flat)map implementation, is the monoid, and thus the monad. Also, Box is a monad in the category of ALL endofunctors on the category of types, and represents a single object. All the individual Box types are objects in the base category of types. You could probably consider these objects with the morphisms defined by the natural transformations to be a subcategory of the category of types, and I believe it would be monoidal, but there would be no monads because it isn't a category of endofunctors. I recognize that this is incredibly pedantic, so anyone who understood the video just fine can ignore this. But if you know a bit of category theory and were having trouble filling in the gaps from this video, I hope this helps some.
I'm not even sure there is a number for how many operators there are. Off the bat, I can think of one non total operator and tons of total ones, so hopefully that answers the question :)
Something I forgot to mention is that in category theory, the "objects" are generally meant to be data structures like groups, as category theory can be vaguely described as group theory but the objects are groups (or replace group with any other structure). This is also why we talk about morphisms, they're the same ones!
The most common joke answer is a burrito. A burrito is just a tortilla containing something, and whats inside doesn't really matter too much. You can open the burrito and modify whats inside (add or remove ingredients) and you end up with another burrito. We can say that this transformation is a functor, since you can pretty much apply a transformation like "add a piece of avocado" to any burrito. However, this functor ends up in the same category of burrito, making it an endofunctor. We could thus say that a burrito is a sort of endofunctor. However, you can combine burritos (remove one tortilla and mix them, for example) while flattening (two burritos give you one). This operation fits the identity (combine with an empty burrito), commutative (if you mix, end result is same no matter the input order) and total (end result is same type as inputs), thus making a monoid. As a result, a burrito is a monad. For real, category theory is all about abstracting abstraction. We can create analogies using real life but not much more than that.
@@AByteofCode i understood nothing 9 months ago when I asked this...but now I watch the video again while studying functional programming and abstract algebra it just makes every sense. Your vid is definitetly the best on this topic bro!
it bugged me for so long why people return M(T) in the mapping function, but that little M(M(T)) => M(T) made everything so clear and me so whole. Edit: wait what? What if the function we are wrapping returns a function instead of a value? How am i supposed to call M(T1=>T2)???
The only way to call M(T1=>T2) is to use the mapping function. You could, for example, apply a value of M(T1) by using the mapping (T1=>T2)=>M(T2), which could be defined using map combined with the value of M(T1). After mapping, this would give a value of type M(M(T2)), and you could then apply the join function to finally get M(T2). If this is confusing, I'd recommend that you play around with a programming language like Haskell which implements Monads and has a nice syntax for working with them.
@@ultimatedude5686 Wow this really is confusing. Thank you very much, I don't yet understand how to get to (T1=>T2) if I have M(T1=T2) which I'm supposed to not treat like a function, but I guess Haskell with help with that
a.map(b.map(c)) so c is a function returning a box because that's the argument map takes. so b.map(c) returns a box and not a function that returns a box. Why can we pass it as a function that returns a box into the a.map call? An instance of the class box is not a function. Isn't that a type error?
I'm not sure I fully get what you mean, but in programming, seeing monads as programmable bullet points is far from the most far fetched monad metaphor I've heard.
also (in an attempt to understand) said "ok so wait categories represent classes where each instance is an object, and objects can be converted into each other with morphisms oh my god that's where polymorphism comes from"
IIRC, polymorphism means that a single interface applies to multiple things. So for example, "+" applies to numbers, lists and strings. While the word "morphism" is in both, I'm not sure they're related in meaning
@@AByteofCode I'm gonna research into type theory and get back to you but even in the way you describe it, that sounds like a morphism to me between objects within the same category
I have a few questions: 1) How can a category 'come along' with an operator? Does that mean that for certain categories specific operators are defined that follow certain properties? Or do the operators define the structure of the category itself? 2) Would it then be correct to say that a category includes morphisms, objects AND optionally, some operators? Thanks! Amazing video
The operator isn't really part of the category at all, it's an additional thing that you can have along with a category. For example a "monoidal category" is a category, an operation on that category, and an object within the category, and some conditions to do with associativity and the identity. Informally you do sometimes end up conflating these sorts of extra structures on categories with the categories themselves, but all that "a category" actually has is objects, morphisms, a way to compose the morphisms (which must be associative), and identity morphisms (which must do nothing when composed with other things). This video misses quite a bit of the actual details imo, if you want to properly understand what's going on I'd recommend using a resource that covers this stuff slower and in more detail.
Wikipedia and nLab are what I've mostly been using to learn this stuff, they're rather information-dense sometimes so it can take some time to understand what on earth they're talking about but when you do that it always ends up working (or at least it always has for me). This video ruclips.net/video/yAi3XWCBkDo/видео.html and the link to a dissertation in a description are also pretty good, they don't cover everything but what they do cover is done slower and with a lot of examples which might be easier than just staring at piles of notation. The video does claim to have asterisks, but having rewatched it, basically everything they say is correct, the only asterisk I can see (other than the things that are intentionally vague) is the fact that they gloss over size issues - technically you can't construct "the category of categories" because that would contain itself and then issues happen, so you actually construct the category of small categories or whatever. It doesn't explain "a monoid in the category of endofunctors", but the dissertation defines natural transformations and monoidal categories, so then you just need monoids, defined here ncatlab.org/nlab/show/monoid+in+a+monoidal+category or here en.wikipedia.org/wiki/Monoid_(category_theory) (these definitions are identical), and the monoidal category of endofunctors, which I haven't managed to find a full description of(...?) but (I think) it's the category in which objects are endofunctors, morphisms are natural transformations, composition of morphisms is vertical composition, product of objects is composition, and product of morphisms is horizontal composition. I suspect the internet in general probably isn't too bad at this if you look for things that are designed to be telling you about general category theory instead of a random SoME2 youtube video trying to explain monads. If you leave out too many details everything will fall apart eventually, so any large internally consistent resource on category theory will probably cover all of what's going on. (They definitely wouldn't be able to get away with this video's definition of "category", which is actually a description of a directed multigraph, not a category; or the definition of "functor", which isn't a description of anything at all because it doesn't actually mean anything)
The thing about a random dude on the internet explaining monads, 100% accurate lol. I'm here to give general ideas of obscure CS stuff, not replace a math teacher :)
An instance of Box is an endofunctor and the Box class is the category of endofunctors? I can't see how this matches the definition of endofunctors and is entirely lost from then on.
A better explanation of a morphism maybe is like moving from a plumbing system of a city to the subway or electricity network, while mantaining some properties.
That's a pretty good analogy, the different systems being structured pretty similarily but while still having differences as to not being the same thing. I like it!
I was following right until the programming came into picture. That was a "draw the rest of the owl" moment for me. What in the Box example is supposed to be X, what are our objects and morphism, what are our endofunctors, what is the monoid operation and where is the identity endofunctor?
Yeah the programming bit was rushed, if it helps, ignore it. What's pretty tricky with the transition to programming is we use the same words for different parts of the same thing. For example, functor is used to refer to the box itself but also the usage of it, which is weird. Otherwise, objects are just any programming object you want, morphisms would become normal operators on those objects, we sort of abstract both of these for the programming monad. The endofunctor is the box (we define a functor as a "box with the function reciever" and the endofunctor in this case is a functor but the return box is of the same type (theoretically if you have two different types of boxes with different extra processing, you could have them return each other and this wouldn't be an endofunctor). Finally, the monoidal operation is when you "flatten" the two boxes back into one at the end of the bind function (you have two boxes and turn them into one, this could be seen as an operator). Since we're trying to make these somewhat practical to use, we are making some analogies, so think of the fact you can pass (x=>x) as a function to the box to have the exact same box after the whole operation, there is an identity. I hope this helped, if it didn't, feel free to ask more questions!
Great video, if you make a video about an example of this in more code that would definitely help! And at 1:25 What does it mean that the end result should not depend on when you went through a functor in the structure? Also wouldn’t all category possess the properties you mentioned making them all semigroups?
Lmao I kinda rushed that part and forgot to mark it as pseudo-code, although you actually could define custom behavior for the operation by giving the class an _ _ add _ _ method.
When it comes to the coding, just write or use the map function without knowing the theory, it's a lot simpler, intuitive and productive. I guess there are a few positions that are theoretical, with budgets >>> time constraints but generally you don't need to know these things, just write the damn code, 30s and you're done:) Excellent explanation tho!
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!
This is literally the best video I've seen what a monad is. Good job!
I always forgot what endofunctors were when thinking about monads, but your description of the "category of endofunctors" being all the possible mappings to itself of another category is simple and easy to understand.
Edit: i think it would have been even better if you added one other code example of a more complicated monad (like Maybe or List)
@@zyansheep Thanks my man! About the edit, you're right I should have added an example of a monad with actual extra logic, but last time I used an example for a monad, that was the only thing a lot of people got out of it, so thought I would better avoid that :/
Your audio has gotten much better
subtitles. NOT hard-subbed (= rendered onto the video), but soft-subbed using youtube's subtitle functionality. simply copy-paste your script. the auto-generated subs aren't always perfect, and especially in a video like this, where every word is chosen carefully, i don't wanna trust a speech-to-text algorithm
@@LastExceed Pasted in the script, ill trust youtube for the timings for now but I'll check it later when I have time
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.
Monad moment :)
Same
functor = mappable stuff
monad = flatmappable stuff
that’s all you need to know as a programmer
@@HcmfWice hey there, would you mind elaborating that a little more?
It's wrong, though.
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.
That is the state monad, there are others which are indispensible even in stateful languages (e.g. lists, promises)
Made me laugh, good one :)
@@scoreunder All of them are variants of state. List and Log monads are an append-only storage, so a log of states, be it meta- (log) or data- (list) oriented. Promise and Await are encoding execution queue capable of wait states into a finite state machine. Maybe is a 'machine has entered invalid state' state.
That is priceless
@@kittysplode The state was already there, natively. It's still out there, truly reflecting the entire state of the program. It must be there for the CPU to work. And you cobble a replacement substitute together on your own, and haul it around everywhere you need it alongside arguments and return values, while the real thing is already everywhere you might need it, except walled away.
Monad: I am a monoid in the category of endofunctors.
Me: I don't even know who you are.
underrated ~
"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
What do you call a person reading a paper on category theory? A co-author :)
A coconut is just a nut.
your momad is a your momoid in the category of endofunctors
@@OliverLugg loconut
@@David-gk2ml it's not a nut
Well, that was the most informed 4 minutes I've wasted in my entire career of coding. I didn't regret.
Glad to hear that lol
what does "a coconut is just a nut" mean in category theory?
Co- basically means "opposite category". So coco- means the opposite of the opposite category.
Me after watching the eightth "intuitive introduction" to a complicated topic, and still not understanding anything about it: 🗿
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.
Indeed. The moment Box(result) becomes self+result I was lost too.
But AFAIU monads in Haskell could be expressed in usual programming terms as 'hiding' in such Boxes some useful payload (with original value) to get extended 'laterial' functionality. And you can put such Boxes to functions which works with original values as expected - and this is all these 'monoids and identity' gibberish are about. If you had function of value sum(value,value) you could call Box sum(Box, Box) and get expected result with some laterial additional computations inside Boxes (for example Box could count up how many additions happend with it's value before). This is why this 'map one category to another' is important in some way.
You should watch the original video he did on monads, really helped apply this video in a new light
I admit the second part was rushed. I was about to leave for holidays and had to rush the ending to upload before the SoMe2 deadline. I'll try my best to not repeat that mistake.
I no longer understand what a monad is.
The math word and the computer word are related but you can understand one without the other. If you understood the design pattern before but now don't, then ignore the last minute of this video which had a bit of unmarked pseudocode which is what I think may have confused you. If there's any conflicting info in your head rn, would you mind telling me what it is so I can clarify?
@@AByteofCode I think you missed the joke.
@@christiansheridan3410 I still do lol, what was it?
@@AByteofCode My view of monads exist in a narrow context. I know what they are from my experience with FP languages. Anything outside of that specific narrow context flies right over my head (especially category theory). It's not that your explanation is bad, it's just that... If someone doesn't have a mathematical background, like myself, it may be futile to explain monads to them in such a way.
@@christiansheridan3410 Hmm I tried making this explanation so that people without a math background would have a chance of understanding. I do see what you mean though
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
You're a genius! Thank you! Both videos actually make so much sense now.
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.
Although I agree, that wasn't in the scope of the video as it was more of a video about category theory, just I had to find some way to justify uploading it on a byte of *code*. I could make a video about the monad types though, with code examples and what problem each one solves.
@WaveHello notice, that what @A Byte of Code explain, requires you to use your brain effort to try and understand the concept. With examples, it would be easier to follow, but it would also be easier to come up with misconceptions, because your brain wouldn't be working as hard.
@@AByteofCode that would be great
@@danielwilkowski5899 In my previous video, I used an example but a lot of people thought that example was the only thing you could do with monads. You hit the nail on the head here!
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(a2BoxB).flatMap(b2BoxC) = 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)
Great explanation! The associativity equality shown at the bottom is what I was going to put but thought it'd be too complicated as a thing to show on screen for a few seconds. Otherwise, the "+" "operator" shown in the code example was meant to encapsulate the idea of flattening but I'll admit I left out too many details in the code part :/
@@AByteofCode I saw that "+" operator and I wondered what the heck it was doing adding two boxes together. It would have been nice to have gotten an explanation.
Wow this helped me understand a lot more after watching the video.
I have been working with flatMap and map in java/scala, and also trying to learn the core functional programming ideas.
It's all starting to connect in my head thanks to this, so I really would like to say thank you!!!
Are there any books on the subject you'd recommend?
@@hotharvey2 I recommend Bartosz Milewski's Category Theory for Programmers, which helped me understand the motivation for functional patterns and category theory in general.
@@C3POtheDragonSlayer I just read the introduction and it seems perfect.
Thanks a lot 😀
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
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
Lmao the last minute isn't that important, was more theoretical than practical (as seen by the ungodly amount of pseudocode i forgot to mention)
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"
Agree. Let me rephrase to hopefully make it clearer. I am just a beginner in category theory. Corrections are welcome.
The category of endofunctors forms a monoidal category. Functor composition acts as the total, associative operator ⊗. Identity functor acts as the identity object I. Inside a monoidal category, if an object M (here objects are endofunctors) equips with two morphisms μ: M ⊗ M → M and η: I → M, then we call it a monoid in this monoidal category. In particular, monoid objects in category of endofunctors are also called monad.
Wiki has more precise definition for monoid: en.m.wikipedia.org/wiki/Monoid_(category_theory)
I found Bartosz's lessons extremely useful for understanding category theory. Despite being theoretical, his presentation is programmer friendly. Highly suggest: ruclips.net/p/PLbgaMIhjbmEnaH_LTkxLI7FMa2HsnawM_
It is weird to put a precise mathematical name to my preferred pattern of programming. I always preferred monads over other type of functions such as functions that change given output parameters.
Now I can sound very pedantic when talking about my program at work: "So the attribute function filter is a monad of the class. Any questions? Oh, of course, I will explain what a monad is. A monad of X is a monoid in the ..."
My dream come true!
This is probably 95% of the usage of the definition and I'm down for it!
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).
Yes, it's pretty abstract when compared with the usual lessons on Objects and OOP (loosely: class is to an object, as a vehicle is to a car)
Monads seem like more of a description of behaviour which is less tangible than object oriented stuff. I would like to point out also, that people tend to see functional programming as a wholly separate ideology and style to OOP, but in reality, if we can understand both and mix+match (e.g rust has great functional aspects) then we will hopefully all be better off.
You're absolutely right! Writing functional code in an OOP codebase is really powerful. Also yeah in general, FP is quite mathematical and not practical, which makes it overall confusing. Then you add vocabulary; a property in math is different to a property in programming, functors sound like functions but aren't, types are classes but not, etc...
Honestly I think videos like this are more likely to contribute to continued skepticism of functional programming instead of winning anyone over.
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.
Yeah lol
Thanks for covering morphisms, functors. Many people skip that bit.
And yes, like others have pointed out, this is by far the crispest explanation.
Few more points that would be good to know.
1.
- Why is the identity needed to make a Monoid?
- What goes wrong if we try to make Monad from a semigroup? and BTW is there a concept of `Group` also?
2. 'Category of endofunctors on a category' Won't that be the category of all morphisms? Or in other words, what is the difference between an endofunctor and a morphism?
@AByteofCode
You kinda just have a table of properties and what you call a set with those properties, so as far as i know some nerd went "yeah monoid is a cool name for this" Also, Group does exist, its just Semigroup but you add Identity and Inverse (which is for each item x there is an item y for which x * y = the identity element).
Otherwise, a morphism is an arrow between two objects, and an endofunctor is an arrow from a category to itself. You could say an endofunctor is a morphism from a category to itself (note the endo prefix) but there is a specific term for arrows between categories so we use that instead.
What you described at 2:41 and 3:14 were not monoids but monoidal categories. A monoid is an object A in a monoidal category (C,x) and a morphism AxA->A satisfying some identities.
So at 3:14 you called (End(X), o) a monad, but really it's just a monoidal category. Monads are monoid objects in (End(X), o), that is, they are special endofunctors of X.
Let the rest catch up first.
yeah this is one of those things which honestly has to be left out of the discussion because it makes it too long. In order to talk about monoidal categories you need to get a little bit into the weeds of their coherence conditions and possibly require an explanation of the tensor product. Both finite products and coproducts can form symmetric monoidal categories, but what that means really depends on how well you understand products and coproducts.
Also there are more abstract definitions were monads are objects in bicategories, which is already losing the spirit of why most programmers care about monads.
It's just too deep for most programmers to deal with at the start.
@@thestemgamer3346
They did talk about monoidal categories in the video, they just (incorrectly) called them monoids while doing so. They could have just mentioned that monoids are objects in the monoidal category they defined and glossed over the associativity and identity conditions given that they already talked about them for monoidal categories.
This isn't a matter of which level of abstraction is relevant. They gave an incorrect definition of monads at the lowest level of abstraction.
A monad is an endofunctor. I don't think incorrectly calling it the category of all endofunctors is more useful to programmers.
Finally, this is a submission to SoME2 a mathematics exposition competition. Of course there should be some level of hand waving to appeal to a lay audience but the definitions should at least be correct, especially when that very definition is the thing being explained.
Yeah it's unfortunate that the original quote wasn't "in the monoidal category of endofunctors". Would've saved many man hours of incorrect explanations (and more hours of people listening to these explanations)
@@TacoDude314 oh I agree, anything incorrect should be called out. Especially when this topic pops up, in the context of computer programming, there are a lot of incorrect definitions. And if you want to treat the subject categorically, you can't really pull any punches.
There are a few other issues with the video, for example, divisibility is not the same as division or inverses (mentioned 2:33). Also map wouldn't form a monoid, it is simply an endofunctor, you would need a different object which encapsulates the composition of multiple maps to be able to form a monoid.
For example, people often confuse the monad object with the object itself. Which isn't really true. Are list's monads, or are they just types in which there exists a monad object which acts through the bind function?
A lot of people assume that lists are monads and functors, because they take typeclasses to be like inheritance and so instancing a typeclass creates this "IS A" relationship in their minds. So a list "IS" a monad to them, when this is really not the case.
Like you mentioned monads are just endofunctors, but it's more than that, they're the endofunctor created by the composition of adjunctions. The monad is just an object that captures that adjunction. How do you explain this to programmers? You don't, so you just don't mention it.
I'm just mentioning that the level of detail required here is often not necessary when addressing this topic to programmers. So it's always going to result in some weird definitions and a lot of missing information. Taking criticism is also an important part of being a content creator too.
Great video. Small pedantic point on my end: at some point you kind of say that regular endomorphisms, unlike endofunctors, don't have an "observable effect" because they don't explicitly define a mapping of the internal structure of objects. This seems to kind of miss the paradigm shift of that makes category theory so powerful, where the observable effects we care about concern the external structure of morphisms, rather than the internal structure of objects. That is to say, the "observable effect" is "observable" in the sense that it interracts with other morphisms around it in a special way.
Very good point
I've seen a bunch of explanations on what a monad is by this point, and this has to be by far the most understandable I've encountered at this point... thanks! I feel like I actually understand this definition properly now!
I still don't understand what a monad is but the video was entertaining. Good job!
After a semester of learning about this I thought I understood monads, thanks for correcting my misunderstanding
Listen to the semester of class over this video. This is a massive oversimplification with more factual issues than I'd like to admit :/
Associativity: exists
IEEE floating point standard: And I took that personally
(with floating point numbers A×B×C doesn't necessarily equal A×C×B due to rounding error, and that's also the reason -ffast-math option exists for many c++ compilers)
A×(B×C)=A×(C×B) is a result of commutativity, not associativity. Associativity is when (A×B)×C = A×(B×C). Commutativity is when A×B=B×A.
This is a nice explanation, dude, keep it up!
Glad you enjoyed! I absolutely intend do :)
"You may have heard that a monad is a monoid in the category of endofunctors" - How did you know? I literally hear this all the time.
Lmao, it definitively depends on the circles you're a part of.
Given that everyone writes monads when they need them, but don't call them this way, I'm still unsure why we need to call them that way or explain them this way.
"A monad is a function that wraps stuff to do (like type validation, error handling) around a value that may (for example) cause troubles if left unchecked. The monad will return the same inout value if it's valid, or a replacement of the desired type, so it's not even ALWAYS an identity."
There.
It's a joke in a blog post called "a brief incomplete and mostly wrong history of programming". It's said by a Haskell programmer in response to "Haskell is too difficult to learn".
The crux of the joke is that it's a mostly useless definition
@@calvinfong7209 uh... I figured. NOW.
There's a lot more things you can do with Monads than just error handling though. You can access an environment or modify a state, for example. In Haskell, the IO monad is the only way to perform side-effects.
@@ultimatedude5686 yep, my simpleton definition was also kind of a joke to counter the ultra-abstract one in the video.
Thnx for the refreshingly-clear explanation 👍
Glad it was helpful!
So there is this thing called category theory and I'm trying to make sense of it. The tool I use to make sense of it is "understanding," which is a functor that returns an updated version of the thing I still call "me". Therefore, understanding is an endofunctor.
If I understand endofunctors *then* understand monoids it's the same as understanding monoids and *then* understanding endofunctors.
Therefore, understanding is a monoid within the category of me.
I think this is still wrong but it's fun. Correct me! What's the right way to write this?
Brief and informative video. Great method to explain!
*misinformative
but to have a monad in computer science you need three different functions
constructor, the map function, and the bind function
The constructor creates instances of Foo
The map function maps transformations of x -> y to Foo(x) -> Foo(y)
The bind function maps transformations of x -> Foo(y) to Foo(x) -> Foo(y)
The original paper about monads in computer science specifies you need all three in order to have any semblance of useful composition.
In C#, "map" is called Select, and "bind" is SelectMany
In JS, Rust, and Scala, "map" is map, and "bind" is flatMap
in Haskell, "map" is map or fmap, and "bind" is >>=
You can construct fmap and join from return and bind. Using only the two methods return and bind was the original Haskell way of defining Monad, which for some reason was not a subclass of Functor. (Haskell also added a fail method, which has no counterpart in category theory and was arguably a design error, because not all monads necessarily have a way to represent failure; think for example of the Identity Monad)
A monad is a gonad that has not yet been invited to the category of exofunctors.
Brilliant, i tried watching and reading tens of videos on category theory and couldnt understand anything due to crappy namings, but now i see it is more simple than those words. Thank you for this brillant video!
I'm glad it helped!
This video deserves definitely a part #2 , also a part #1
This video deserves recursive sequels
The WHAT also yes considering how many mistakes I made I'm gonna need to make 10 correction videos about it lol
This video is simply wonderful. Thank you!
Thanks for the kind words!
Good explainer, congrats!! Perfectly clear now.
I'm very happy to hear that!
This explanation is utterly satisfying if you already know what a monad is.
Yea, i agree, that's one of the best monad explanations available on youtube! I firstly thought it will be another "monad is just pattern", but it was clear and correct explaniation! Good Job!
(sorrry for bad english)
Well I also happen to have a video about it being a pattern, just wanted to explain the deadly sentence as well :) Thank you very much, and don't worry about the english!
The most interesting things about monads is, i can do safe IO operation when wrapping IO operation inside "monad-like" types in imperative language, this also can make me write less boilerplate code for error checking.
Is it important for the function input type to match the function output type? I raised this question in SO and was told that every type belongs to the same category! So the function can take in an integer (a type) and return a string (also a type) - and nothing is violated. (Of course I am omitting the generics with templates here for simplicity).
A monad can be seen as a mapping between types, together a mapping between functions (between types). So given types X and Y, you'll get M[X] and M[Y], and given f : X → Y, you'll get M(f) : M[X] → M[Y]. And in addition you have M : X → M[X], and it all needs to fit together with the function chaining (M(f ° g) = M(f)°M(g), M(f(x)) = M(f)(M(x)), etc.)
M[_] might be a generic type (that's the common case), or it might be a constant type, or some complicated type function.
The input and output types don't matter. The point of monads (or functors in general) is that the external type (the box) is what matters and stays the same, so usually, unless specific differently, the insides can change type.
this explanation is amazingly smoothly done
The first part of the video was excellent, but when you started explaining the connection to programming, it would be great if you slowed down and showed the correspondence between terms in category theory and terms in programming
SS: YES, straight to the point, I love this format.
Glad to hear that!
i need an explanation of the explanation
Are there any specific bits you didn't get or is it just the whole thing? Feel free to add me on discord (username is iwaroz) and we can call.
I can't believe I finally understand the shit!
I've come across this years ago. I can't believe it had always been so simple.
You've made me feel like a moron and a genius at the same time, congratulations
Thank you! I'm glad I could help!
This is interesting and I think that it would make sense for you to go further on the topic please 🙏🏼 find out the time and the energy we all need to have more because it was just not enough 😅
So if you're crying about pointers, think about monads
Wonderful breakdown and explanation
If I cared more I would understand. However, I can appreciate how much effort you put into the animations.
Thank you, this was much more clear than programming books trying to explain by analogy instead of using mathematics, which made no sense to me.
Finally someone cuts to the chase and just explains it. THANK YOU.
3:35 - "this box right here" what exactly is this sentence referring to? the arrow points to `self.value` which is not a box (except for nested boxes, but that wasn't mentioned anywhere)
3:46 - what does it mean to add a box to another box ? the code shown here throws a type error (TypeError: unsupported operand type(s) for +: 'Box' and 'Box'). the following explanation "the rest of the method is simply combining two boxes in order to return one" doesnt explain *how* this combination works either
3:58 - the receiver of the latter `map` in the second line is a function instead of a box, which means its a completely different function that just happens to have the same name. how is this a valid comparison ? and why isn't this mentioned?
Well, what I can make out is that 'self.value' can be of any type, including but not necessarily a 'Box' object. And 'map' returns a 'Box' object of any value, from the existing instance of 'Box' class.
So, you can pass 'map' method a theoretical 'function' argument that return a new 'Box' instance that has as its 'value' the original 'Box' the method instance belongs to. Resulting, in short, with a "NewBox.value == OldBox". So "OldBox.map(func).value = OldBox". And that's as far as I got.
Because, when he makes the equality "a.map(b).map(c) = a.map(b.map(c))" the obvious problem here is that the 'map' method only takes another method. But 'b' is treated as both a method and a 'Box' class object which makes no sense and pretty much turns the last 30 seconds of the video into non-sense for me as well.
Oh god that CS part was scuffed lol. "this box right here" was meant to point at the class in general, and the + and associativity maps were pseudocode that I forgot to mention as such. I'm very sorry about all of that :|
@Nicholas Preda line 1: yes
line 2: say the 'function' is a box factory, when called with the value of the previous box, you get a new box. I didn't explain how the combination worked because that is a per-implementation specific detail, and last time I mentionned implementation specifics people thought that was the only option :/
line 3: what I meant was that if we got rid of the "calling the function part" and just assumed that map just took boxes directly, then the map things work.
@@nicholaspreda90 You're being quite the pentagonator.
I am not a category theory specialist, but to make your explanation truly usefull, you should mention the flatMap, which allows to composite monads. As if you return a Promise from a Promise, it is still a Promise, this operation makes monad whatever the definition says.
i understood monads but now i understand the bad description of it
I'll need a minute to take in everything that you present in this vid - but I think if I try I actually _will_ be able to understand it, since the explanation is clear. Thanks!
The virgin repeater vs. the Chad corrector (of monad definitions)
The first part was really intuitive, thanks for that. Up to the point, what it all ment. The last part was a bit on a rush. But I understand, that this video was ment to be a short introduction, so maybe that wasn‘t even your intention.
What are the morphisms in the category of endofunctors of X?
so what's the difference between a monoid in a category, compared to an ordinary abstract-algebra monoid? I assume it has to at least satisfy some additional coherence constraints? Being *in* a category, does that mean it's a special kind of object or a morphism or something different? Maybe it's a morphism mapping from products?
went to a bootcamp, they thought monads was a good topic for a 3 day r&d project... horrible experience but today I understand why, thank you
I think the biggest misstep in this otherwise flawless video is this: right at the end, you blaze through all that math you've carefully built up and just assert that it is what it is in code. It's not clear what makes map an endofunctor, what the category is (Box or the object it holds?), or why we can call that a category. The transformation undergone through that endofunctor is also vague.
Oh, and on second thought, I'm docking 10 points for sticking an undefined and totally handwaved addition operation in there between a value of type Box and the value returned from func.
But how is monad related to side effects? That's its sales pitch in haskell.
This video was awesome! And I love how straightforward the box type is 😁. Would have loved an extra 30 seconds showing how to use this in a productive way! Like, how this translates into an 'IOMonad'
Eventually, I'll make a practical video about monads, but i don't want half my channel to be about them either so it'll probably be in a while :/
Can you please elaborate more on functors,
like how will it map morphisms and objects in two different categories? And what are these morphisms and objects that are being mapped in terms of programming...
Plus, how do endofunctors map to themselves
Gotta remember that at its core, category theory is all about abstracting abstraction and that functors are purely theoretical ideas. The question of "how" as a generality thus doesn't make much sense.
You can do whatever mappings you want however you want them. The only rules for you to be able to call them functors are that every single object & morphism from A must map to something in B (plus a consistency thing explained in the video). Take the category of positive numbers and the category of negative numbers (we'll define morphisms as being +1 or -1 depending on which ctgry). You can create a functor by mapping the number 1 to -1, number 2 to -2 and so on, then map the arrow "1 to 2" to "-1 to -2" and so on. This is just one example, you can make whatever objects you want (objects are generally data like numbers, strings, bools, custom classes, etc) and morphisms are just things you can do to a piece of data to make it another piece of data of the same type.
An endofunctor just means you have the same category at the start and the end. For example one endofunctor on numbers could be "1 to 2" and "2 to 3" and so on with mapping the "1->2" arrow to the "2->3" arrow, etc.
If I haven't answered your question in a satisfying way let me know!
@@AByteofCode thanks for responding, this whole thing just feels like an abstraction over/a subset of relationship algebra.
@@jimitsoni18 I don't have any experience with relationship algebra but the if you think its abstracting something then you're probably right :)
Can you make more videos on category theory
Are there any specific topics you'd want talked about? Otherwise I do have long term plans for a series about abstract algebra which would certainly have an episode about categories
I am filled with regret for the day I became curious about what a Monad is after a computerphile video, so I searched for it, and now my feed is filled with Monad explainers that don't help me understand Monads. I've long since stopped caring, but keep being recommended more or less accurate-according-to-comments and jargon-heavy videos, this is my new hell. Thanks for trying, though.
The classic monad experience :)
Only way to escape it is to make your own monad video that noone else will understand!
What is a diffrence between endomorphism and identity function?
That's a good question! I'd say that an endomorphism is given to a specific object, whereas an identity function applies to all objects, but as far as I know, the line is a bit blurry between the two words
@@AByteofCode An identity arrow is the unique endomorphism which serves as a unit under composition of arrows. This should feel like a monoid.
I don't know how to write a class in C++ for my project, and here i am watching a video about monads.
Understanding the theory is honestly way better than people trying to jump straight into code. I've watched and read multiple posts/vids about monoids and this really helps fix up the gaps. Thanks!
I'm glad to have helped!
I know that concepts click at different times for different people. Some may find this too advanced and some may find it too simplistic. But it was exactly at the conscise-but-precise level I needed to FINALLY feel for the first time like I understood the diabolic sentence! Now let's see how long that feeling lasts :).
Thank you very much, great video!
This is close enough to get by, but there are some terminology mix-ups that might be confusing to some:
You claim to have a category of endofunctors, but you really just have a bunch of endofunctors. Without the morphisms, it's not really clear what this category even is. In the case of the category of endofunctors, the morphisms are natural transformations.
Once you give it the bifunctor (operator), it doesn't become a monoid itself, it becomes a monoidal category. A monoid is an object in that category along with a pair of morphisms that take elements from the respective product object and identity object into itself. Because the objects are endofunctors in X and the morphisms are natural transformations in X, that monoid object is called a monad in X.
For a type constructor like Box to be a monad, it needs a few things: (1) a way to turn any object into a "wrapped" one, i.e. a constructor, (2) a way to turn any function between types into a function between "wrapped" types, i.e. a map implementation, and (3) a way to turn a "doubly wrapped" object into a "singly wrapped" one, i.e. a flatten implementation. You can get away with implementing just a flatmap to get (2) and (3) in one go, which is what you do here after supposing that f returns a Box type.
You call "map" a monoid in the category of boxes, but a monoid is an object and the objects in our category are endofunctors, which "map" is not an example of. Instead, the type constructor Box, with the object constructor and the (flat)map implementation, is the monoid, and thus the monad. Also, Box is a monad in the category of ALL endofunctors on the category of types, and represents a single object. All the individual Box types are objects in the base category of types. You could probably consider these objects with the morphisms defined by the natural transformations to be a subcategory of the category of types, and I believe it would be monoidal, but there would be no monads because it isn't a category of endofunctors.
I recognize that this is incredibly pedantic, so anyone who understood the video just fine can ignore this. But if you know a bit of category theory and were having trouble filling in the gaps from this video, I hope this helps some.
Can't wait to flaunt the upgraded superior variant "a monad in X is just a monoid in the category of endofunctors of X"
Honestly can't believe you did this in 4 minutes.
2:06 What do you mean by "most operators are total"? How many of them are total, and how many are not?
I'm not even sure there is a number for how many operators there are. Off the bat, I can think of one non total operator and tons of total ones, so hopefully that answers the question :)
this category theory thing reminds me of group theory
Something I forgot to mention is that in category theory, the "objects" are generally meant to be data structures like groups, as category theory can be vaguely described as group theory but the objects are groups (or replace group with any other structure). This is also why we talk about morphisms, they're the same ones!
What’s the irl object/concept that resembles a monad the most?
The most common joke answer is a burrito. A burrito is just a tortilla containing something, and whats inside doesn't really matter too much. You can open the burrito and modify whats inside (add or remove ingredients) and you end up with another burrito. We can say that this transformation is a functor, since you can pretty much apply a transformation like "add a piece of avocado" to any burrito. However, this functor ends up in the same category of burrito, making it an endofunctor. We could thus say that a burrito is a sort of endofunctor. However, you can combine burritos (remove one tortilla and mix them, for example) while flattening (two burritos give you one). This operation fits the identity (combine with an empty burrito), commutative (if you mix, end result is same no matter the input order) and total (end result is same type as inputs), thus making a monoid. As a result, a burrito is a monad.
For real, category theory is all about abstracting abstraction. We can create analogies using real life but not much more than that.
@@AByteofCode i understood nothing 9 months ago when I asked this...but now I watch the video again while studying functional programming and abstract algebra it just makes every sense. Your vid is definitetly the best on this topic bro!
@@GoddamnAxl Thank you :D I appreciate the kind words!
it bugged me for so long why people return M(T) in the mapping function, but that little M(M(T)) => M(T) made everything so clear and me so whole.
Edit: wait what? What if the function we are wrapping returns a function instead of a value? How am i supposed to call M(T1=>T2)???
The only way to call M(T1=>T2) is to use the mapping function. You could, for example, apply a value of M(T1) by using the mapping (T1=>T2)=>M(T2), which could be defined using map combined with the value of M(T1). After mapping, this would give a value of type M(M(T2)), and you could then apply the join function to finally get M(T2). If this is confusing, I'd recommend that you play around with a programming language like Haskell which implements Monads and has a nice syntax for working with them.
@@ultimatedude5686 Wow this really is confusing. Thank you very much, I don't yet understand how to get to (T1=>T2) if I have M(T1=T2) which I'm supposed to not treat like a function, but I guess Haskell with help with that
@@iliya-malecki If you have a M(T1 => T2), and a function (T1 => T2) => T3, you can get an M(T3).
@@ultimatedude5686 okay now it is perfectly clear, thank you so much
Oh wow, there are two monad explanations submitted for SoMe2 now. This is gonna get interesting...
And both submissions were contributed to by the person who made the other submission :) We were gonna make one together but ended up not
okay but what about comonads??
Not too sure, but I do know what a cocomonad is :)
It's like a monad but in the reverse ;)
a.map(b.map(c))
so c is a function returning a box because that's the argument map takes. so b.map(c) returns a box and not a function that returns a box. Why can we pass it as a function that returns a box into the a.map call? An instance of the class box is not a function. Isn't that a type error?
Is monad considered also a bullet points that we use?
I'm not sure I fully get what you mean, but in programming, seeing monads as programmable bullet points is far from the most far fetched monad metaphor I've heard.
me hearing "endofunctors map each object to another object in the category" and instantly saying "group theory? :)" out loud
also (in an attempt to understand) said "ok so wait categories represent classes where each instance is an object, and objects can be converted into each other with morphisms oh my god that's where polymorphism comes from"
IIRC, polymorphism means that a single interface applies to multiple things. So for example, "+" applies to numbers, lists and strings. While the word "morphism" is in both, I'm not sure they're related in meaning
Yes! There are categories whose objects are groups and whose arrows are group homomorphisms. I wonder what monads we might find there.
@@AByteofCode I'm gonna research into type theory and get back to you but even in the way you describe it, that sounds like a morphism to me between objects within the same category
Great explanation!! Your videos thumbnail seems to make me wanna watch it even if I don't want to learn what monad is.
Thank you so much!
Any applications or use of such strange entities in the real world??? How would one implement such in code? Find it very interesting though.
If haskell counts as the real world, then yes. Otherwise, promises in javascript are monads, and so are lists when using flatMap.
I have a few questions:
1) How can a category 'come along' with an operator? Does that mean that for certain categories specific operators are defined that follow certain properties? Or do the operators define the structure of the category itself?
2) Would it then be correct to say that a category includes morphisms, objects AND optionally, some operators?
Thanks! Amazing video
The operator isn't really part of the category at all, it's an additional thing that you can have along with a category. For example a "monoidal category" is a category, an operation on that category, and an object within the category, and some conditions to do with associativity and the identity. Informally you do sometimes end up conflating these sorts of extra structures on categories with the categories themselves, but all that "a category" actually has is objects, morphisms, a way to compose the morphisms (which must be associative), and identity morphisms (which must do nothing when composed with other things).
This video misses quite a bit of the actual details imo, if you want to properly understand what's going on I'd recommend using a resource that covers this stuff slower and in more detail.
Thanks! Any such resources that you would specifically recommend?
Wikipedia and nLab are what I've mostly been using to learn this stuff, they're rather information-dense sometimes so it can take some time to understand what on earth they're talking about but when you do that it always ends up working (or at least it always has for me).
This video ruclips.net/video/yAi3XWCBkDo/видео.html and the link to a dissertation in a description are also pretty good, they don't cover everything but what they do cover is done slower and with a lot of examples which might be easier than just staring at piles of notation. The video does claim to have asterisks, but having rewatched it, basically everything they say is correct, the only asterisk I can see (other than the things that are intentionally vague) is the fact that they gloss over size issues - technically you can't construct "the category of categories" because that would contain itself and then issues happen, so you actually construct the category of small categories or whatever. It doesn't explain "a monoid in the category of endofunctors", but the dissertation defines natural transformations and monoidal categories, so then you just need monoids, defined here ncatlab.org/nlab/show/monoid+in+a+monoidal+category or here en.wikipedia.org/wiki/Monoid_(category_theory) (these definitions are identical), and the monoidal category of endofunctors, which I haven't managed to find a full description of(...?) but (I think) it's the category in which objects are endofunctors, morphisms are natural transformations, composition of morphisms is vertical composition, product of objects is composition, and product of morphisms is horizontal composition.
I suspect the internet in general probably isn't too bad at this if you look for things that are designed to be telling you about general category theory instead of a random SoME2 youtube video trying to explain monads. If you leave out too many details everything will fall apart eventually, so any large internally consistent resource on category theory will probably cover all of what's going on. (They definitely wouldn't be able to get away with this video's definition of "category", which is actually a description of a directed multigraph, not a category; or the definition of "functor", which isn't a description of anything at all because it doesn't actually mean anything)
👍I'll be on the lookout for resources
The thing about a random dude on the internet explaining monads, 100% accurate lol. I'm here to give general ideas of obscure CS stuff, not replace a math teacher :)
An instance of Box is an endofunctor and the Box class is the category of endofunctors? I can't see how this matches the definition of endofunctors and is entirely lost from then on.
Such a clear explanation and yet I'm still confused
"Now we understand", "We know" 😂
"If anything doesn't make sense" 😅
A better explanation of a morphism maybe is like moving from a plumbing system of a city to the subway or electricity network, while mantaining some properties.
That's a pretty good analogy, the different systems being structured pretty similarily but while still having differences as to not being the same thing. I like it!
I was following right until the programming came into picture. That was a "draw the rest of the owl" moment for me. What in the Box example is supposed to be X, what are our objects and morphism, what are our endofunctors, what is the monoid operation and where is the identity endofunctor?
Yeah the programming bit was rushed, if it helps, ignore it.
What's pretty tricky with the transition to programming is we use the same words for different parts of the same thing. For example, functor is used to refer to the box itself but also the usage of it, which is weird. Otherwise, objects are just any programming object you want, morphisms would become normal operators on those objects, we sort of abstract both of these for the programming monad. The endofunctor is the box (we define a functor as a "box with the function reciever" and the endofunctor in this case is a functor but the return box is of the same type (theoretically if you have two different types of boxes with different extra processing, you could have them return each other and this wouldn't be an endofunctor). Finally, the monoidal operation is when you "flatten" the two boxes back into one at the end of the bind function (you have two boxes and turn them into one, this could be seen as an operator). Since we're trying to make these somewhat practical to use, we are making some analogies, so think of the fact you can pass (x=>x) as a function to the box to have the exact same box after the whole operation, there is an identity.
I hope this helped, if it didn't, feel free to ask more questions!
Is the map function you're referring to is actually flatmap from Java and Scala? I though map actually didn't flatten the result.
JavaScript. map doesn't flatten but flatMap does :)
this is the best ever explanation
Thank you!
When he said 'arrows' I got that
Great video, if you make a video about an example of this in more code that would definitely help! And at 1:25 What does it mean that the end result should not depend on when you went through a functor in the structure? Also wouldn’t all category possess the properties you mentioned making them all semigroups?
Didn’t stemgamer do a video on this exact same topic for some2 like a month ago
He helped me with this video a bit. We were gonna do his together but didn't and just both made our own versions seperately.
I don't understand how you can "add two Boxes". does the "+" operator used on objects have some meaning in python?
Lmao I kinda rushed that part and forgot to mark it as pseudo-code, although you actually could define custom behavior for the operation by giving the class an _ _ add _ _ method.
When it comes to the coding, just write or use the map function without knowing the theory, it's a lot simpler, intuitive and productive. I guess there are a few positions that are theoretical, with budgets >>> time constraints but generally you don't need to know these things, just write the damn code, 30s and you're done:) Excellent explanation tho!