Hello, for all of those confused about this post not being a meme. Also some clarifications for the future: This is my submission for the Summer of Math Exposition 2 ran by 3Blue1Brown. You can find more info here: ruclips.net/video/hZuYICAEN9Y/видео.html I also ran a community poll and the majority voted in favour of this video in particular. Memes will continue as usual. In the meantime come check out the discord server to let me know what you want to see next (link in desc). If this does well maybe I'll make some more! Some clarifications, NO a Monad is NOT A MONOID in the category of endofunctors, it is a Monoid Object in the tensor category, BUT this is significantly harder to explain and I don't want to get into monoidal categories or tensor products. Maybe in another video.
It probably won't do that well, considering it's your first video in this style, so it doesn't quite have a viewerbase, yet. I think you should make one every once in a while and see if it will catch on with time. So far I like this style.
What's a monad? A monad is a monoid in the category of endofunctors. What's a monoid? It's what a monad is in the category of endofunctors. What's an endofunctor? It's the thing that comprises the category in which a monad is a monoid. What's a category? There are some things you just aren't meant to know.
This was an amazing video, _especially_ coming from a literal meme channel. You made this video your own with your own style, you're more than just the other manim-using channels that look exactly like 3Blue1Brown but sped up. This has my vote for sure
You bring up Rust, which does have Option and Result as true monads, with the Try trait acting as a limited form of the Monad type class (traits and type classes are basically just the same thing), but implemented a little more obtusely due to Rust's type system. Iterators in Rust though I'm not sure are truely monads, because I don't think they're actually endofunctors. Monoids and functors yes as far as I'm aware, but not _endofunctors._ This is because Iterator is not one type, but is its own trait, and the bind operator (called flat_map) doesn't actually give the same type as the previous iterator, but rather a completely different type that still implements the Iterator trait. Effectively flat_map :: a i -> (i -> b j) -> FlatMap (a i) (i -> b j). The output has a completely different context from the input. This is because 1) Every function in Rust has its own type to help with static dispatch, and 2) this is how Rust makes its iterators lazy without native lazy evaluation.
I'm a pure mathematician/physicist that got into programming and it couldn't have been a better combination. More programming concepts should be put in terms of their real mathematical counterparts without fearing people won't understand nor care.
In pure functional programming, there is no state. Everything is immutable; and every computation needs to be describeable as a mathematical function. To add to that, GHC (the haskell compiler) was initially made as an experiment to see how well pure functional languages mix with laziness; and it inherits a lot of the ML (Meta Language) roots; which are mainly that they take a lot from mathematics and category theory. It makes sense if you think about it, since category theory works within the bounds of mathematics yet describes a lot of interesting things. And because of that, you have this FP jargon. For most people, they start learning these things with Functors, which you can think of as values inside a box or a context. A couple examples for Functors are 1. lists, where the "context" is multiple values of the same type, and 2. optional values, the context being "this value may not exist", so a `Maybe Int` would be either a `Just Int` or a `Nothing`. These Functors need to have a function `fmap` to map the values under the context. That function for a list type is obvious, it would be `fmap (+1) [1,2,3]`, which returns `[2, 3, 4]`. for `Maybe Int`'s, there are two cases. `fmap (+1) (Just 1)` which would return `Just 2`, or `fmap (+1) Nothing` which would be `Nothing`. Then, something kind of important is getting the concept of Monoids. A simple explanation is that a type would be a monoid if there's a function `a -> a -> a` (`a` being a generic type), this (called `mappend`) function takes 2 `a`s and returns an `a`. it needs to be associative. and finally, there needs to be an "identity" value `mempty`. a value that, if the function was called with mempty and another value of that type, the other value would be returned. An example of a monoid is integers under addition; as that forms a monoid because the "identity" is 0 in addition, and the associative function is `+`. Other monoids are lists and strings. And also, integers are also monoids under multiplication. Finally, applicative functors. Earlier, with functors; the `fmap` function took a function, and applied it to a value under a context. With applicative functors, even the function is under a context. This is a natural point to get to, because if you had a function that takes more than 1 argument, you'd need applicative functors. They define the operation `ap`, which you'd run as `ap (Just (+1)) (Just 1)`, and you could use with fmap like: `ap (fmap (+) (Just 1)) (Just 2)`. Also, applicatives define a function called `pure` which returns the minimal value in a context; so for a list, `pure 1` would be `[1]`, for a `Maybe Int`, `pure 1` would be `Just 1`, etc. That was all before monads. See, all monads are applicative functors. They are the most used method of sequencing effects or actions (meanwhile monoids sequence values). And that is the main reason they're used. To easily get an effect ran before the other, maybe bound to a name as well. To get that, they had to also have a way to collapse contexts; so make a `Just (Just 1)` become a `Just 1` via the `join` function by `join (Just (Just 1))`. That's necessary because, in a pure world, nesting is one of the only ways to sequence effects. Collapsing that information into one structure makes it easier to work with. that, and also because pure languages only evaluate the outer `IO` context of effects that do I/O. so in a `IO (IO ())` type, the outer one would be evaluated whatever it does, with the inside one being ignored. Monads allow them both to be evaluated by collapsing the contexts. And people call monads "a monoid in the category of endofunctors" for a reason; first off, all functors in haskell are endofunctors. secondly, let's look back at 2 important functions. the `pure` function, which is of the type `a -> m a`, and the `join` function, which is of the type ` m (m a) -> m a` . if you squint (i can make this more equivalent but it'd take me writing much more in YT comment), then these functions are like the mempty and mappend in the context of functors. `pure` is like `mempty` because, if you use natural transformations, it'd be `() ~> m`, which is isomorphic (meaning equal or similar) to mempty, since mempty returns a value like `mempty :: a`, it is isomorphic to a function that has the type `() -> a`, since it cant add more data. `join` is like mappend because it takes 2 functors, similarly to how mappend takes 2 values, and smashes them together into one functor, like mappend smashes values into one value.
I'd like to add that gender is a topological space and sexuality is a diagraph where the vertices are the subsets of the sets of points in the gender space and there are directed edges going from a singleton to all other vertices.
I've always had them explained to me as: Functor: anything with a map method (e.g. array, future, list) Monoid: anything appendable (string, array, list, future) Endofunctor: anything that you can map to it's same category Monad: anything with a flatmap method Which yeah, lots of "normal", boring things like lists fall into that category, but that's the point. The only things that are excluded are the hard things (like state), so you can focus on that stuff in one place rather than spread out throughout your whole program.
flatmap is one way to think about it, makes more sense with the list monad though, since a flat map doesn't quite make the most intuitive sense with things like the maybe or either monad.
I personally find the flattening part to be quite intutive, even for maybe and either monads. I think about it as collaping everything into a single level.
The editing is so trippy I was more focused on how the hell you did all of that than the actual explanations. Pro tip: use fairlight's noise suppression tools to remove the background noise, and when recording VsCode, increase the native zoom of the app instead of doing it during editing.
It's important to note that there's both monoids in the original abstract algebraic sense, and monoids in a more generalized categorical sense. A monad doesn't act on a set, it's a monoid object in the monoidal category of endofunctors.
yeah this is a good point and I omitted this on purpose because this video isn't meant for category theorists because they already know this stuff. I mention in the disclaimer I'd rather not talking about monoidal categories and tensors. If you don't know what a monoid is, you won't know what a tensor is, or a monoidal category, or a category for that matter. Waste of time and makes everyone more confused. The point was to get people to intuitively understand the idea of what a monad represents and how that pattern is already quite prevalent across software engineering as a whole.
@@thestemgamer3346 Still, though, I'm honestly not sure that a handwavey explanation of what it means to be a monoid in the category of endofunctors is less confusing than simply introducing the interface that corresponds to (map, join, and return), modulo issues of actually writing it as a trait due to a lack of higher kinded types. And in both cases, there's a certain amount of "so what?" until you see practical examples of using flatmap / >>= to solve annoying problems.
Regarding the famous phrase: From what I understand, types of a programcing language are objects in a category and functions are the arrows between them, and for example, wrapping types in `List` and their corresponding functions in `map(…)` is an endofunctor because it maps that category to itself? And in this case the binary operator of the monoid is the operator that turns two layers of the "wrap types in List and wrap functions in map(…)" operation into one layer? It's what Haskell calls `join`, not `>>=`. I.e. join (map . map) === map
As far as I understand, it's a little bit different. The only object in the category of endofunctors of, say, List is a single object containing types List. The arrows are morphisms List -> List and they're also themselves the endofunctors. Note, the List is itself a functor A -> List. Let's call it T. Monad is defined by a triplet (T, mu, nu) where mu and nu a natural transformations. Natural transformation transform a functor to another functor. mu: T x T -> T, a.k.a. `join`. nu: I -> T, a.k.a.`return`, I is the Identity endofunctor. You have to define these two to define monad for the same reason you have to define operation and neutral element for monoid. E.g. {Z+, +, 0} and {Z+, ×, 1} both define a monoid over Z+. There might be more than one way to do so.
@@skyeplus Oh, yeah I had forgotten about needing to define ν, but what you said matches my vague understanding (I haven't formally studied category theory). A subtle part (for me) is that the µ and ν transformations in category theory correspond to the operations on *types* in Haskell, not the operations on data. Manipulating data is an afterthought.
@@SimonClarkstone It does both, actually. It tells a specific way on how to transform the values. It's a functor over functor, or in practical terms a function over function. For instance, join takes List(List(X)) and constructs a new List by joining inner lists sequentially. Theoretically, one might define a different method of flattening a list of lists.
@@skyeplus Ah, I see. Though in Haskell specifically, List can only be an instance of Monad in one way at a time, right? (Like how Integer has two obvious Monoid definitions but Haskell can't use both without newtype to distinguish them.)
@@SimonClarkstone Yes, List as it is an already defined type would require a new type (like NonEmpty list). Probably a list which either empty or a single value list could be a monad, because it's essentially the Maybe monad.
Well done on the video OP, but I can't but feel you never gave why a monad is a monoid in the catergory of endofunctors - you told us what they were but not why they fit. Perhaps a section on the monoid properties (tensor and unit) being fufilled by composition and return
Yeah I omitted a lot of that on purpose. If you read the disclaimer I put in the middle I mention that I purposefully ignored talking about those sorts of things because it honestly just makes everything harder to understand for most people. This video is meant for people who program who have heard the term but never really had it explained. Not really meant for category theorists, since you probably already know what a monad is anyways. However I do plan a follow up video where maybe I talk a little bit more about monoidal categories and tensor products and how it all comes together. It's just wayy too much to cover and will cause the viewer to get more lost.
@@thestemgamer3346 sounds good, keep it up (: these resources weren’t around when I started 14 years ago and it was an uphill struggle. These make all the difference, should be proud of yourself.
This is incredibly fascinating, and really well explained! Please do make another one of these! Other than that I have only one thing to say: the editing is pretty insane. It's clean and fluid and snappy, and I can tell you know your way around Manim. on the other hand, because everything was constantly moving, and some code was on screen for barely a second after it was typed out... I couldn't keep my eyes on any one spot to take in what's being written. That made some scenes feel way busier than they had to, and it was super distracting! So for your next one I'd just recommend slowing down the pace a bit, and toning down the editing slightly. That'll make everything easier to follow.
Thank you, I think because I spend so long editing the video I just got so used to seeing the images that I didn't realize how long they were on screen for. While editing it felt a lot longer, but then again I often stared at a lot of still frames.
So, if I understand correctly, a monad is a set of functions(that map values from a set to values from the same set) which can be composed together? I.e. in rust: let data = Option.map(|x| x + 1).filter(|x| x.is_positive()); Or also with iterators: let data = vec![1, 2, 3].into_iter().map(|x| x+1).filter(|x| x & 1 == 0).enumerate();
This has been one of the best descriptions I've heard. I already knew some Haskell and understood the concepts (both monoid and monads) but seeing the graphical examples, seeing the translation of the expression was really great! Great content, congratulations for being so awesome
Yeah you're right, but this also means I have to talk about associativity, which I omitted cause I didn't think it was particularly useful for understanding what a monad is essentially doing to data
Monads to me are one of those things that I don't quite know what they are, but I know them when I see them. And that didn't change with this video unfortunately, guess it would have been nice to pay attention in uni math classes
Exist an blog called: "Category Theory for Programmers" that explains the mostly of terms about Category Theory in a way easy to understand "for programmers", for somebody who is interested, I recommend it so much. These blog explains also some strategies and models used for functional languages, but you can also apply in imperative languages.
Good video, I was struggling with the explanations of a monad as a begginer programmer and mathmatician, you are a great teacher, and the editing is on point :cheffkiss:
I really liked this type of video and really hope you make more in the future. I think you did a really good job explaining. I only knew set theory coming into this but I feel like you gave us a very "elevator pitch" version of category theory and monads which is (imo) the best way to go about doing explainers.
Really good explanation and break down of monads and some of the surrounding concepts for monads.Looking forward to seeing more long form videos alongside the fun stuff.
I loved this video, nice to learn about some of the mathematical background of computer science and language design! If you ask me, keep it coming! (In between some dank meme vids)
I wonder if I'll understand that after the video, but for now as I watch entertain yourself with this A vector is an object that transforms like a vector. And A tensor is an object that transforms like a tensor. Have fun people
Came to find out what a monad is - left confused and thinking that its literally an OO object whose sole purpose is to aggregate other objects. Am I silly here?
I think this subject is close to impossible to condensate in 20 mins or less... IMHO it is better to just accept that it is a complicated subject and each of individual words needs an entire course, and then an entire course to put all together and then a video for each instance and example of monoids and monads.
I always forget what a monoid is. I mean, why do they call it monoid if it's between a group and a semigroup? In German it's Gruppe (group) and Halbgruppe (=semigroup = half group), so I jokingly call it 3/4 group, which is easier to remember than monoid...
@@swagatochatterjee7104 the English Wikipedia entry for Monoid (NOT from category theory) shows a ln overview, according to that there is a inverse semigroup, which has associativity and division. Unless I forgot I think I've only heard of semigroup, monoid and group, and MAYBE magma...
I've been studying a lot of category theory over the years so nerd warning, but I think this explanations were actually pretty good, but it also did feel like two explanations in one (i.e monads in category theory vs monads in programming). If there's any suggestion I could make- and again this is just some nerd's two cents don't take this as sacred or anything- something that might have better connected the two concepts would be to define the structure in terms of return and join. Especially since closed endofunctors (or applicatives, as Haskell calls them) are becoming more commonplace, and sometimes it's shorter and easier to read when using ap ( in Haskell) and join rather than bind, join is becoming more popular anyways. Still a great video though, and I would defo recommend it to anybody who's just getting into the concept!
I can tell this video had a lot of effort put into it and I appreciate the simplification you made but I still don't understand D: the closest my mind comes to understanding what a monad is is just that it's data and functions that manipulate the data encapsulated in a context like a class except designed more for the ability to put an "if" statement in mathematics For some serious feedback I feel like there's some parts the video goes too fast. Specifically in the code portions when you would provide code examples it felt like they would disappear before anyone could possibly have a chance to read it all
Thanks, you can always pause the videos, but I think it would have been helpful if I held the images longer. Also you are kind of close to what a monad is. You are essentially describing a way to control some state over time. It is the only way to do "imperative Haskell".
As much as I enjoy the memes, this is great content. Honestly, a lot of this still went over my head but from what I could pick up it was still interesting.
There can be no slandering R. Even shit R code runs much faster than equivalent python. Not to mention using R has a pre-requisite of knowing advanced statistics.
The most oversimplified explanation of what a monad is that I can think of, based purely on the contents of this video, is some sort of context that contains data and has chain-able methods for you to modify that data without changing the context itself.
I really had to laugh out at revisiting the monoid definition. Its just many fabcy words describing concepts chained together that normal programmers know by heart.
So in short, a monad is a class/type/object that wraps some value and comes with a bind operation, which takes a function and applies it to the wrapped value. Did i get it right?
Meh. To be honest, everybody is overcomplicating this topic. A monad is simply a type, an interface. You can think about this as a class or something. Monad has two methods: one to create a monad out of value X, and second (called bind), that has very specific interface (accepts the monad with value X, and a callback that accepts value X and returns a new monad of the same type). That's basically it, and nothing more. Whatever monad is doing is actually hidden behind a bind method implementation of given monad - which can differ from monad to monad. The nice thing about this interface is that it is composable/chainable. And this allows you to work "in context" of monad: that is applying sequence of transformations (binds). And that's it basically.
In practice that's essentially what it forms, particularly in Haskell when using the Monad typeclass. So you're more or less on the money. Although technically a Monad also has a rigorous definition so one does need to be cautious when over simplifying it, which I did kind of do. You don't need to do any kind of inheritance to actually get a Monad tho
@@thestemgamer3346 Not sure about what inheritance you are talking, but yeah, the bind function besides type has also to conform to monadic laws. Technically if it doesn't conform to these laws, other functions (from libraries or something) - that can work on generic monads - can provide false results.
@@thestemgamer3346 From my pov, this is the real value of FP and all the energy that I spend understanding this over and over again since my university times. This had nothing to do with inheritance. Actually it makes you less and less dependent on inheritance at all, either the good format, by listening what Barbara Liskov said either the bad format that we all do the entire day to deliver code. I know after some years as a developer that inheriting and extending through inheritance is a cheap way to easily move your cards on JIRA. But it's like on real life that you call yourself a financially successful person just because your parents have billions on their accounts. So having a sane way to make composition first class and first choice and still achieve something that can be reused for years is what learning monads is all bout. Don't forget why some of us are still insisting on this topic and we shall continue explaining monads in 1000's of different ways. Keep it up!
just stay away from OOP and you are already ahead of most programmers out there 😉😁😝 edit: the author was just being politically correct by mentioning java here🤣
Pretty good explanation but if I have to critique one thing: many of the code snippets shown were on screen for such a short time that they were more a distraction than supporting the explanation. Had to constantly pause which becomes an annoying chore after the 10th time.
Very good material and great montage, the only thing that would make it perfect is a better microphone, which is a little bit to quiet and contains some noise
I'm surprised you didn't mention async in JS or Rust as that's also a monad, specifically one that causes all sorts of problems for programmers who have to jump in and out of it. In fact, this problem even has a name: they call it "function coloring", after a rant called "What color is your function". At least in Rust you can't exactly tell the trait system what a Monad actually *is* (we need higher-kindedness to write "bind") so you can't write proper monad/color-invariant functions in that language. But if you could it would significantly reduce the hassle of writing async code in languages with async syntax.
No joke, I think it was good. It is incredibly difficult subject to explain to the point I stopped long ago - I will refer people to this (I think monoids could be expanded upon, I would stress they are "unescapable").
This is a very well done video, but I have a difficult time telling what you are saying throughout the video without replaying parts several times, because it sorta sounds like you are faintly mumbling very quickly. For example, at the beginning of the "Categories and Endofunctors" section you say what sounds like, "You have the initial collection of objects shshshabhch sets, and a collection of functions between those sets, called arrows or morsms, or mrrrps." You also tend to combine several sentences in a kind of run-on way, like where you are talking about the Option pseudo-monad in Rust in the second half. I hope I am not coming across harshly, the actual content of the video is very good. I would love to see more content like this but I hope if there is more that you will work on the dictation.
At 6:00 you seem to imply that a Monad is a collection of endofunctors equipped with composition as a product between them. You even wrote (F, G) |-> G o F, but this is not right. Composition is supposed to replace the Cartesian product, a Monad is a single endofunctors F and a map F o F -> F. Just like a monoid in Set is a single set E and a map ExE -> E. For example the thing that makes List into a Monad is that we have a map List List x -> List x that takes a list of lists and flattens it.
Most of your video is about bind. Given a map a -> F a, then since F is a functor we can lift this to get a map F a -> F F a. Then since we have a map F F a -> F a we can compose to get a map F a -> F a. This is how we get bind from the definition of a Monad.
@@thestemgamer3346 i would think its too low in some parts. Its probably an issue of audio normalisation. Check this out: ruclips.net/video/OKSWPrT5upo/видео.html
„If the potential of every number is in the monad, then the monad would be intelligible number in the strict sense, since it is not yet manifesting anything actual, but everything conceptually together in it.“ - Iamblichus On the Monad The Theology of Arithmetic Almost all Gnostic systems of the Syrian or Egyptian type taught that the universe began with an original, unknowable God, referred to as the Parent or Bythos, or as the Monad by Monoimus. "He is the invisible Spirit, of whom it is not right to think of him as a god, or something similar. For he is more than a god, since there is nothing above him, for no one lords it over him. For he does not exist in something inferior to him, since everything exists in him. For it is he who establishes himself. He is eternal, since he does not need anything. For he is total perfection. A being can have a relationship with a God but not the Monad as that would be a contradiction." - The Apocryphon of John, 180 AD.
@@thestemgamer3346 face reveal video idea: make a video where you take off a ski mask and underneath it's the rust logo printed out and stuck on ur facs
@@mastershooter64 rewrite the dream face reveal in Rust I do have plans for what I'd do for a face reveal some time, but that's a long time away so I won't worry about it yet.
I think the example at 13:47 is wrong, it needs brackets around the final return since it's flatmap instead of map. It's also clearer with parentheses imo: [1, 2, 3] >>= ( -> ("Hi" >>= (\ch -> [([n+1, n*2], ch)]))) And then the do notation version should be foo :: [([Int], Char)] foo = do n
I loved it! But… isn’t the identity function for a set of real numbers multiplication by one? My understanding is… weak. If I’m wrong please try to explain clearly!
Would be nice if there was something aimed at mathematicians explaining monads. When you search for intuition for monads nearly every single thing is aimed at programmers.
good video i think but am i the only one thinking the dynamic range is too high? a lot of times i couldn’t make out what you’re saying you just went quiet out of nowhere
Audacity noise cancelling often does more harm than good, use different software and don't over process it. For a mic get a Snowball or whatever it's called, near professional audio can be had for under $100 in hardware. I recommend getting a stand, otherwise desk vibrations while typing will make you sad. I picked one up at Guitar Center for about $30.
Hello, for all of those confused about this post not being a meme. Also some clarifications for the future:
This is my submission for the Summer of Math Exposition 2 ran by 3Blue1Brown.
You can find more info here:
ruclips.net/video/hZuYICAEN9Y/видео.html
I also ran a community poll and the majority voted in favour of this video in particular.
Memes will continue as usual. In the meantime come check out the discord server to let me know what you want to see next (link in desc).
If this does well maybe I'll make some more!
Some clarifications, NO a Monad is NOT A MONOID in the category of endofunctors, it is a Monoid Object in the tensor category, BUT this is significantly harder to explain and I don't want to get into monoidal categories or tensor products. Maybe in another video.
It probably won't do that well, considering it's your first video in this style, so it doesn't quite have a viewerbase, yet. I think you should make one every once in a while and see if it will catch on with time. So far I like this style.
Cool stuff! :) I hope you do well
Bruh you didn't put #SoME2 in the title :)
Also a suggestion if you have got the time then do add subtitles to the video :)
@@arsilvyfish11 fixed
If you watch the video backwards, it teaches comonads
This was good
Now I can confidently say:
A monad is just a monoid in the category of endofunctors. What's the problem?
It's not a monoid, it's only a monoidal object.
A monad is just a monoid in the category of endofunctors
thanks, it explains everything and I unsubscibed channel after seeing this comment :)
a gonad is just a gonoid in the category of endofucktors
Bro is speaking the language of gods
Sounds like some artifact from an RPG game
Nerd
What's a monad? A monad is a monoid in the category of endofunctors.
What's a monoid? It's what a monad is in the category of endofunctors.
What's an endofunctor? It's the thing that comprises the category in which a monad is a monoid.
What's a category? There are some things you just aren't meant to know.
This was an amazing video, _especially_ coming from a literal meme channel. You made this video your own with your own style, you're more than just the other manim-using channels that look exactly like 3Blue1Brown but sped up.
This has my vote for sure
You bring up Rust, which does have Option and Result as true monads, with the Try trait acting as a limited form of the Monad type class (traits and type classes are basically just the same thing), but implemented a little more obtusely due to Rust's type system.
Iterators in Rust though I'm not sure are truely monads, because I don't think they're actually endofunctors. Monoids and functors yes as far as I'm aware, but not _endofunctors._ This is because Iterator is not one type, but is its own trait, and the bind operator (called flat_map) doesn't actually give the same type as the previous iterator, but rather a completely different type that still implements the Iterator trait. Effectively flat_map :: a i -> (i -> b j) -> FlatMap (a i) (i -> b j). The output has a completely different context from the input. This is because 1) Every function in Rust has its own type to help with static dispatch, and 2) this is how Rust makes its iterators lazy without native lazy evaluation.
I'm a pure mathematician/physicist that got into programming and it couldn't have been a better combination. More programming concepts should be put in terms of their real mathematical counterparts without fearing people won't understand nor care.
if people doing understand, it can't be used lul
You guys just use your pure functional programming, and leave us mere mortals with more comprehensible less abstract concepts.
On the other hand, i finally understood the summation symbol when someone showed what it would look like as a foreach loop
In pure functional programming, there is no state. Everything is immutable; and every computation needs to be describeable as a mathematical function. To add to that, GHC (the haskell compiler) was initially made as an experiment to see how well pure functional languages mix with laziness; and it inherits a lot of the ML (Meta Language) roots; which are mainly that they take a lot from mathematics and category theory. It makes sense if you think about it, since category theory works within the bounds of mathematics yet describes a lot of interesting things. And because of that, you have this FP jargon. For most people, they start learning these things with Functors, which you can think of as values inside a box or a context. A couple examples for Functors are 1. lists, where the "context" is multiple values of the same type, and 2. optional values, the context being "this value may not exist", so a `Maybe Int` would be either a `Just Int` or a `Nothing`. These Functors need to have a function `fmap` to map the values under the context. That function for a list type is obvious, it would be `fmap (+1) [1,2,3]`, which returns `[2, 3, 4]`. for `Maybe Int`'s, there are two cases. `fmap (+1) (Just 1)` which would return `Just 2`, or `fmap (+1) Nothing` which would be `Nothing`.
Then, something kind of important is getting the concept of Monoids. A simple explanation is that a type would be a monoid if there's a function `a -> a -> a` (`a` being a generic type), this (called `mappend`) function takes 2 `a`s and returns an `a`. it needs to be associative. and finally, there needs to be an "identity" value `mempty`. a value that, if the function was called with mempty and another value of that type, the other value would be returned. An example of a monoid is integers under addition; as that forms a monoid because the "identity" is 0 in addition, and the associative function is `+`. Other monoids are lists and strings. And also, integers are also monoids under multiplication.
Finally, applicative functors. Earlier, with functors; the `fmap` function took a function, and applied it to a value under a context. With applicative functors, even the function is under a context. This is a natural point to get to, because if you had a function that takes more than 1 argument, you'd need applicative functors. They define the operation `ap`, which you'd run as `ap (Just (+1)) (Just 1)`, and you could use with fmap like: `ap (fmap (+) (Just 1)) (Just 2)`. Also, applicatives define a function called `pure` which returns the minimal value in a context; so for a list, `pure 1` would be `[1]`, for a `Maybe Int`, `pure 1` would be `Just 1`, etc.
That was all before monads. See, all monads are applicative functors. They are the most used method of sequencing effects or actions (meanwhile monoids sequence values). And that is the main reason they're used. To easily get an effect ran before the other, maybe bound to a name as well. To get that, they had to also have a way to collapse contexts; so make a `Just (Just 1)` become a `Just 1` via the `join` function by `join (Just (Just 1))`. That's necessary because, in a pure world, nesting is one of the only ways to sequence effects. Collapsing that information into one structure makes it easier to work with. that, and also because pure languages only evaluate the outer `IO` context of effects that do I/O. so in a `IO (IO ())` type, the outer one would be evaluated whatever it does, with the inside one being ignored. Monads allow them both to be evaluated by collapsing the contexts.
And people call monads "a monoid in the category of endofunctors" for a reason; first off, all functors in haskell are endofunctors. secondly, let's look back at 2 important functions. the `pure` function, which is of the type `a -> m a`, and the `join` function, which is of the type ` m (m a) -> m a` . if you squint (i can make this more equivalent but it'd take me writing much more in YT comment), then these functions are like the mempty and mappend in the context of functors. `pure` is like `mempty` because, if you use natural transformations, it'd be `() ~> m`, which is isomorphic (meaning equal or similar) to mempty, since mempty returns a value like `mempty :: a`, it is isomorphic to a function that has the type `() -> a`, since it cant add more data. `join` is like mappend because it takes 2 functors, similarly to how mappend takes 2 values, and smashes them together into one functor, like mappend smashes values into one value.
I'd like to add that gender is a topological space and sexuality is a diagraph where the vertices are the subsets of the sets of points in the gender space and there are directed edges going from a singleton to all other vertices.
@@srijanpaul You'd do great in homotopy type theory!
someone pin this man
- 🤓 🤓 🤓
@@alpindale 😭😭😭
I've always had them explained to me as:
Functor: anything with a map method (e.g. array, future, list)
Monoid: anything appendable (string, array, list, future)
Endofunctor: anything that you can map to it's same category
Monad: anything with a flatmap method
Which yeah, lots of "normal", boring things like lists fall into that category, but that's the point. The only things that are excluded are the hard things (like state), so you can focus on that stuff in one place rather than spread out throughout your whole program.
flatmap is one way to think about it, makes more sense with the list monad though, since a flat map doesn't quite make the most intuitive sense with things like the maybe or either monad.
I personally find the flattening part to be quite intutive, even for maybe and either monads. I think about it as collaping everything into a single level.
these trailers are trippy as hell
That epic moment when a monad is a monoid in the category of endofunctors
Dude you actually made a Monad Tutorial!
I guess this makes me officially a Haskell programmer right?
@@thestemgamer3346 that just makes a you an anarchist... Afraid of states
@@irithylloldman6526 no the state monad only hides the states from the plain view so that's deep state
@@irithylloldman6526 😂😂😂
@@irithylloldman6526 good one
The editing is so trippy I was more focused on how the hell you did all of that than the actual explanations.
Pro tip: use fairlight's noise suppression tools to remove the background noise, and when recording VsCode, increase the native zoom of the app instead of doing it during editing.
Exactly! The voice was closed to un-understandable.
Apologies, I did use the noise canceling feature in audacity, maybe my hearing is just messed up because I did not hear any hissing while editing
@@thestemgamer3346 Kwool!
Love ur content and delivery!🔥🙌
@@thestemgamer3346 Its not the hissing, its just the way you talk, inconsistent tone, volume and pacing, nasal voice, mangled syllables, etc etc.
@@thestemgamer3346 Do you have a video on your approach to animation? I'd like to see that.
It's important to note that there's both monoids in the original abstract algebraic sense, and monoids in a more generalized categorical sense. A monad doesn't act on a set, it's a monoid object in the monoidal category of endofunctors.
yeah this is a good point and I omitted this on purpose because this video isn't meant for category theorists because they already know this stuff. I mention in the disclaimer I'd rather not talking about monoidal categories and tensors.
If you don't know what a monoid is, you won't know what a tensor is, or a monoidal category, or a category for that matter. Waste of time and makes everyone more confused. The point was to get people to intuitively understand the idea of what a monad represents and how that pattern is already quite prevalent across software engineering as a whole.
@@thestemgamer3346 Still, though, I'm honestly not sure that a handwavey explanation of what it means to be a monoid in the category of endofunctors is less confusing than simply introducing the interface that corresponds to (map, join, and return), modulo issues of actually writing it as a trait due to a lack of higher kinded types. And in both cases, there's a certain amount of "so what?" until you see practical examples of using flatmap / >>= to solve annoying problems.
Yessss. I was waiting for a more long-form programming video! This channel is going nuts!
Regarding the famous phrase:
From what I understand, types of a programcing language are objects in a category and functions are the arrows between them, and for example, wrapping types in `List` and their corresponding functions in `map(…)` is an endofunctor because it maps that category to itself? And in this case the binary operator of the monoid is the operator that turns two layers of the "wrap types in List and wrap functions in map(…)" operation into one layer? It's what Haskell calls `join`, not `>>=`.
I.e. join (map . map) === map
As far as I understand, it's a little bit different. The only object in the category of endofunctors of, say, List is a single object containing types List. The arrows are morphisms List -> List and they're also themselves the endofunctors.
Note, the List is itself a functor A -> List. Let's call it T.
Monad is defined by a triplet (T, mu, nu) where mu and nu a natural transformations. Natural transformation transform a functor to another functor.
mu: T x T -> T, a.k.a. `join`.
nu: I -> T, a.k.a.`return`, I is the Identity endofunctor.
You have to define these two to define monad for the same reason you have to define operation and neutral element for monoid. E.g. {Z+, +, 0} and {Z+, ×, 1} both define a monoid over Z+. There might be more than one way to do so.
@@skyeplus Oh, yeah I had forgotten about needing to define ν, but what you said matches my vague understanding (I haven't formally studied category theory).
A subtle part (for me) is that the µ and ν transformations in category theory correspond to the operations on *types* in Haskell, not the operations on data. Manipulating data is an afterthought.
@@SimonClarkstone It does both, actually. It tells a specific way on how to transform the values. It's a functor over functor, or in practical terms a function over function. For instance, join takes List(List(X)) and constructs a new List by joining inner lists sequentially. Theoretically, one might define a different method of flattening a list of lists.
@@skyeplus Ah, I see. Though in Haskell specifically, List can only be an instance of Monad in one way at a time, right?
(Like how Integer has two obvious Monoid definitions but Haskell can't use both without newtype to distinguish them.)
@@SimonClarkstone Yes, List as it is an already defined type would require a new type (like NonEmpty list). Probably a list which either empty or a single value list could be a monad, because it's essentially the Maybe monad.
Terminator is just an android in category of endoskeletons!
I just started learning Haskell 💀, guess imma go to Julia for maths..
Now I know why a monad is a monoid in the category of endofunctors.
I was reading the whole categories for working mathematics book just to understand what a monad is. This video came up in my feed at the perfect time.
Well done. Hope the submission does well. Was both entertaining and informative.
Well done on the video OP, but I can't but feel you never gave why a monad is a monoid in the catergory of endofunctors - you told us what they were but not why they fit. Perhaps a section on the monoid properties (tensor and unit) being fufilled by composition and return
Yeah I omitted a lot of that on purpose. If you read the disclaimer I put in the middle I mention that I purposefully ignored talking about those sorts of things because it honestly just makes everything harder to understand for most people.
This video is meant for people who program who have heard the term but never really had it explained. Not really meant for category theorists, since you probably already know what a monad is anyways.
However I do plan a follow up video where maybe I talk a little bit more about monoidal categories and tensor products and how it all comes together. It's just wayy too much to cover and will cause the viewer to get more lost.
@@thestemgamer3346 sounds good, keep it up (: these resources weren’t around when I started 14 years ago and it was an uphill struggle. These make all the difference, should be proud of yourself.
This is incredibly fascinating, and really well explained! Please do make another one of these! Other than that I have only one thing to say: the editing is pretty insane. It's clean and fluid and snappy, and I can tell you know your way around Manim.
on the other hand, because everything was constantly moving, and some code was on screen for barely a second after it was typed out... I couldn't keep my eyes on any one spot to take in what's being written. That made some scenes feel way busier than they had to, and it was super distracting!
So for your next one I'd just recommend slowing down the pace a bit, and toning down the editing slightly. That'll make everything easier to follow.
Thank you, I think because I spend so long editing the video I just got so used to seeing the images that I didn't realize how long they were on screen for.
While editing it felt a lot longer, but then again I often stared at a lot of still frames.
Hands down the BEST monad explanation ever!!! You've earned a sub, well done👍
So, if I understand correctly, a monad is a set of functions(that map values from a set to values from the same set) which can be composed together?
I.e. in rust:
let data = Option.map(|x| x + 1).filter(|x| x.is_positive());
Or also with iterators:
let data = vec![1, 2, 3].into_iter().map(|x| x+1).filter(|x| x & 1 == 0).enumerate();
This has been one of the best descriptions I've heard. I already knew some Haskell and understood the concepts (both monoid and monads) but seeing the graphical examples, seeing the translation of the expression was really great!
Great content, congratulations for being so awesome
Wait, this isn't a meme? I have been tricked but it's a great video. Keep making more like these.
honestly the restatement of the quote at 1:50 cleared up like 80% of the questions i had (but didn't bother to explore) lmao. thanks for this video
A monoid is also a semigroup, meaning the binary operation also needs to be associative.
Yeah you're right, but this also means I have to talk about associativity, which I omitted cause I didn't think it was particularly useful for understanding what a monad is essentially doing to data
This channel literally made me interested in learning Rust. Thanks
Monads to me are one of those things that I don't quite know what they are, but I know them when I see them. And that didn't change with this video unfortunately, guess it would have been nice to pay attention in uni math classes
same bro same
Exist an blog called: "Category Theory for Programmers" that explains the mostly of terms about Category Theory in a way easy to understand "for programmers", for somebody who is interested, I recommend it so much.
These blog explains also some strategies and models used for functional languages, but you can also apply in imperative languages.
brilliant video m8. Very helpful. Now I can meme more educatedly
Good video, I was struggling with the explanations of a monad as a begginer programmer and mathmatician, you are a great teacher, and the editing is on point :cheffkiss:
if you love MONADS you'll love MYNADS
Saved for next time I need to explain monad to friend (I was told we shouldn’t do that, but I don’t care)! I love your animation style.
I really liked this type of video and really hope you make more in the future. I think you did a really good job explaining. I only knew set theory coming into this but I feel like you gave us a very "elevator pitch" version of category theory and monads which is (imo) the best way to go about doing explainers.
1:51 YES, that's exactly the music that plays in my head.
So this is the Monado's power!
Great video, hopefully we'll see more of these
This is an extremely made video omg keep up the work
Really good explanation and break down of monads and some of the surrounding concepts for monads.Looking forward to seeing more long form videos alongside the fun stuff.
are you becoming lessons in meme culture but for programming?
But did scientists really quantum entangle tardigrades?
I don't know if they have. But what I know is the wave function collapse is kind of monadic.
You are participating to #SoME2, great! Good luck!
The first 7 min in this video is the best explanation for monads i've seen so far
I loved this video, nice to learn about some of the mathematical background of computer science and language design! If you ask me, keep it coming! (In between some dank meme vids)
this is the best video on monads i have seen in my life, and i believe i have seen every single one in existence
I wonder if I'll understand that after the video, but for now as I watch entertain yourself with this
A vector is an object that transforms like a vector.
And
A tensor is an object that transforms like a tensor.
Have fun people
And the tensor product is a coproduct in the Category of commutative Rings
😀
Came to find out what a monad is - left confused and thinking that its literally an OO object whose sole purpose is to aggregate other objects. Am I silly here?
I think this subject is close to impossible to condensate in 20 mins or less... IMHO it is better to just accept that it is a complicated subject and each of individual words needs an entire course, and then an entire course to put all together and then a video for each instance and example of monoids and monads.
Agree, there so much to explore and unravel, but it would take a whole series likely.
6:46 The dichotomy between small categories and non-small categories was omitted too.
The Motion Graphics and the video is on point
I always forget what a monoid is.
I mean, why do they call it monoid if it's between a group and a semigroup? In German it's Gruppe (group) and Halbgruppe (=semigroup = half group), so I jokingly call it 3/4 group, which is easier to remember than monoid...
I always call it inverse free group on my head
@@swagatochatterjee7104 the English Wikipedia entry for Monoid (NOT from category theory) shows a ln overview, according to that there is a inverse semigroup, which has associativity and division.
Unless I forgot I think I've only heard of semigroup, monoid and group, and MAYBE magma...
I'm so used to the stupid "monoid in category" meme that I end up remember just from that now lmao
Mono is Latin for 1. A monoid is a semigroup with 1 (with identity).
I've been studying a lot of category theory over the years so nerd warning, but I think this explanations were actually pretty good, but it also did feel like two explanations in one (i.e monads in category theory vs monads in programming). If there's any suggestion I could make- and again this is just some nerd's two cents don't take this as sacred or anything- something that might have better connected the two concepts would be to define the structure in terms of return and join. Especially since closed endofunctors (or applicatives, as Haskell calls them) are becoming more commonplace, and sometimes it's shorter and easier to read when using ap ( in Haskell) and join rather than bind, join is becoming more popular anyways. Still a great video though, and I would defo recommend it to anybody who's just getting into the concept!
I can tell this video had a lot of effort put into it and I appreciate the simplification you made but I still don't understand D: the closest my mind comes to understanding what a monad is is just that it's data and functions that manipulate the data encapsulated in a context like a class except designed more for the ability to put an "if" statement in mathematics
For some serious feedback I feel like there's some parts the video goes too fast. Specifically in the code portions when you would provide code examples it felt like they would disappear before anyone could possibly have a chance to read it all
Thanks, you can always pause the videos, but I think it would have been helpful if I held the images longer.
Also you are kind of close to what a monad is. You are essentially describing a way to control some state over time. It is the only way to do "imperative Haskell".
As much as I enjoy the memes, this is great content. Honestly, a lot of this still went over my head but from what I could pick up it was still interesting.
R slander?
I'll start, when they choose python over R for anything other than Biostatistics
There can be no slandering R. Even shit R code runs much faster than equivalent python. Not to mention using R has a pre-requisite of knowing advanced statistics.
@@adivp7 yet more people use python for machine learning afaik
@@co9681 Well, it's easier to use Python obviously.
@@adivp7 especially with powerful libraries like tensorflow/keras, pytorch, scikit... Etc. I still value R for it's statistics features.
Tfw weak security
The most oversimplified explanation of what a monad is that I can think of, based purely on the contents of this video, is some sort of context that contains data and has chain-able methods for you to modify that data without changing the context itself.
I really had to laugh out at revisiting the monoid definition.
Its just many fabcy words describing concepts chained together that normal programmers know by heart.
holy shit this one's good, SoME2 is going to be awesome
So in short, a monad is a class/type/object that wraps some value and comes with a bind operation, which takes a function and applies it to the wrapped value. Did i get it right?
What I understand Monad is it run the transformation inside a context and the result is still in a context.
Damn, that monad definition really rivals "a tensor is something that transforms like a tensor" in unhelpfulness
I love this kind of content
Meh. To be honest, everybody is overcomplicating this topic.
A monad is simply a type, an interface. You can think about this as a class or something.
Monad has two methods: one to create a monad out of value X, and second (called bind), that has very specific interface (accepts the monad with value X, and a callback that accepts value X and returns a new monad of the same type).
That's basically it, and nothing more.
Whatever monad is doing is actually hidden behind a bind method implementation of given monad - which can differ from monad to monad.
The nice thing about this interface is that it is composable/chainable. And this allows you to work "in context" of monad: that is applying sequence of transformations (binds).
And that's it basically.
In practice that's essentially what it forms, particularly in Haskell when using the Monad typeclass.
So you're more or less on the money.
Although technically a Monad also has a rigorous definition so one does need to be cautious when over simplifying it, which I did kind of do.
You don't need to do any kind of inheritance to actually get a Monad tho
@@thestemgamer3346 Not sure about what inheritance you are talking, but yeah, the bind function besides type has also to conform to monadic laws.
Technically if it doesn't conform to these laws, other functions (from libraries or something) - that can work on generic monads - can provide false results.
@@thestemgamer3346 From my pov, this is the real value of FP and all the energy that I spend understanding this over and over again since my university times. This had nothing to do with inheritance. Actually it makes you less and less dependent on inheritance at all, either the good format, by listening what Barbara Liskov said either the bad format that we all do the entire day to deliver code.
I know after some years as a developer that inheriting and extending through inheritance is a cheap way to easily move your cards on JIRA.
But it's like on real life that you call yourself a financially successful person just because your parents have billions on their accounts.
So having a sane way to make composition first class and first choice and still achieve something that can be reused for years is what learning monads is all bout. Don't forget why some of us are still insisting on this topic and we shall continue explaining monads in 1000's of different ways.
Keep it up!
I tried to research it for the meme and gave up 2 minutes in
Thank you for this video
I'm new to programming. I wonder if I will ever learn this.
Some day, you should try Haskell and Rust
just stay away from OOP and you are already ahead of most programmers out there 😉😁😝
edit: the author was just being politically correct by mentioning java here🤣
Pretty good explanation but if I have to critique one thing: many of the code snippets shown were on screen for such a short time that they were more a distraction than supporting the explanation. Had to constantly pause which becomes an annoying chore after the 10th time.
I'll keep that in mind for future.
You should do more tutorial videos
Very good material and great montage, the only thing that would make it perfect is a better microphone, which is a little bit to quiet and contains some noise
I'm surprised you didn't mention async in JS or Rust as that's also a monad, specifically one that causes all sorts of problems for programmers who have to jump in and out of it. In fact, this problem even has a name: they call it "function coloring", after a rant called "What color is your function".
At least in Rust you can't exactly tell the trait system what a Monad actually *is* (we need higher-kindedness to write "bind") so you can't write proper monad/color-invariant functions in that language. But if you could it would significantly reduce the hassle of writing async code in languages with async syntax.
The intro is gold
Ah, yes, monoids in the category of endofunctors 🤤
fascinating and informative! Thanks.
So a monad is literally just a function that returns a reference to "this", if we go by C++ / C# / Java terms.
No joke, I think it was good. It is incredibly difficult subject to explain to the point I stopped long ago - I will refer people to this (I think monoids could be expanded upon, I would stress they are "unescapable").
i dont know anything about programming and im still here idk why
Note that Functor in Haskell is theoretically endofunctor.
This is a very well done video, but I have a difficult time telling what you are saying throughout the video without replaying parts several times, because it sorta sounds like you are faintly mumbling very quickly. For example, at the beginning of the "Categories and Endofunctors" section you say what sounds like, "You have the initial collection of objects shshshabhch sets, and a collection of functions between those sets, called arrows or morsms, or mrrrps." You also tend to combine several sentences in a kind of run-on way, like where you are talking about the Option pseudo-monad in Rust in the second half.
I hope I am not coming across harshly, the actual content of the video is very good. I would love to see more content like this but I hope if there is more that you will work on the dictation.
At 6:00 you seem to imply that a Monad is a collection of endofunctors equipped with composition as a product between them. You even wrote (F, G) |-> G o F, but this is not right.
Composition is supposed to replace the Cartesian product, a Monad is a single endofunctors F and a map F o F -> F. Just like a monoid in Set is a single set E and a map ExE -> E.
For example the thing that makes List into a Monad is that we have a map List List x -> List x that takes a list of lists and flattens it.
Most of your video is about bind. Given a map a -> F a, then since F is a functor we can lift this to get a map F a -> F F a. Then since we have a map F F a -> F a we can compose to get a map F a -> F a. This is how we get bind from the definition of a Monad.
loved the format, but u gotta work on the delivery. i heard it comes with practice so keep em coming!
I have some newer ones planned which will hopefully have some better quality, the gain on my mic might be too high
@@thestemgamer3346 i would think its too low in some parts. Its probably an issue of audio normalisation. Check this out: ruclips.net/video/OKSWPrT5upo/видео.html
„If the potential of every number is in the monad, then the monad would be intelligible number in the strict sense, since it is not yet manifesting anything actual, but everything conceptually together in it.“
- Iamblichus On the Monad
The Theology of Arithmetic
Almost all Gnostic systems of the Syrian or Egyptian type taught that the universe began with an original, unknowable God, referred to as the Parent or Bythos, or as the Monad by Monoimus.
"He is the invisible Spirit, of whom it is not right to think of him as a god, or something similar. For he is more than a god, since there is nothing above him, for no one lords it over him. For he does not exist in something inferior to him, since everything exists in him. For it is he who establishes himself. He is eternal, since he does not need anything. For he is total perfection. A being can have a relationship with a God but not the Monad as that would be a contradiction."
- The Apocryphon of John, 180 AD.
Ok but, face reveal at 10k????
no promises
@@thestemgamer3346 If you are a crab, this will boost your channel's population!
@@thestemgamer3346 face reveal video idea: make a video where you take off a ski mask and underneath it's the rust logo printed out and stuck on ur facs
@@mastershooter64 rewrite the dream face reveal in Rust
I do have plans for what I'd do for a face reveal some time, but that's a long time away so I won't worry about it yet.
Category theory: making the simple difficult since it was invented
Nice, explanation
Now I actually know what a monad is... I think
Lots of manim being used here, such a great library
I think the example at 13:47 is wrong, it needs brackets around the final return since it's flatmap instead of map. It's also clearer with parentheses imo:
[1, 2, 3] >>= (
-> ("Hi" >>= (\ch -> [([n+1, n*2], ch)])))
And then the do notation version should be
foo :: [([Int], Char)]
foo = do
n
Can we fact check this?
I loved it! But… isn’t the identity function for a set of real numbers multiplication by one?
My understanding is… weak. If I’m wrong please try to explain clearly!
Feedback: The video production is very good, and the script is also good, but your audio quality and manner of speaking are not great.
Yes, the voice-over was really fast with not enough articulation.
Wierd to see your voice but I love it!
Would be nice if there was something aimed at mathematicians explaining monads. When you search for intuition for monads nearly every single thing is aimed at programmers.
Poor Ferris looked so confused :(
I'm surprised someone created Rust bindings for Manim.
so basically you transform the functions instead of passing value?
good video i think but am i the only one thinking the dynamic range is too high? a lot of times i couldn’t make out what you’re saying you just went quiet out of nowhere
This is really hard to understand acoustically for some reason
Audacity noise cancelling often does more harm than good, use different software and don't over process it.
For a mic get a Snowball or whatever it's called, near professional audio can be had for under $100 in hardware. I recommend getting a stand, otherwise desk vibrations while typing will make you sad. I picked one up at Guitar Center for about $30.
This was your long game right here. We just all got Rick Rolled. Banana Banana Banana Banana, Banana Banana!