How Monoids are useful in Programming?

Поделиться
HTML-код
  • Опубликовано: 2 янв 2025

Комментарии • 124

  • @badwolf8112
    @badwolf8112 4 года назад +243

    I THINK FORBIDDING LOWERCASE CHARACTERS WOULD BE A GREAT RESTRICTION.

  • @red_reaper128
    @red_reaper128 5 лет назад +191

    Now that's a epic haskell programming video

  • @valigotech
    @valigotech 5 лет назад +124

    I have shown this video to my React codebase. It turned into Elm

    • @MorganEarlJones
      @MorganEarlJones 5 лет назад +24

      I showed this video to my Elm project. It turned into PureScript

    • @asdfghyter
      @asdfghyter 5 лет назад +8

      Nazarii Bardiuk My arch installation has actually gradually turned into NixOS. I’ve basically stopped using pacman now.

    • @MrRedstonefreedom
      @MrRedstonefreedom Год назад

      These kinds of expressions are trivial to do in JS. I've treated predicates in this sort of way in JS probably a couple hundreds of times. You can even implement a pipe() like haskell's "do" with like three LOCs. Although unlike lisp you can't define your own syntax to go along with the implementation :((( , but i don't think haskell can do so either.

    • @AndreiGeorgescu-j9p
      @AndreiGeorgescu-j9p 10 месяцев назад +1

      ​@@MrRedstonefreedomyou have monoids in js? And not sure how do is relevant or how any of this is "trivial" when the average js dev can't even go outside without a helmet

  • @joriskbos1115
    @joriskbos1115 4 года назад +49

    Whenever he says "what do I need for that?" The answer is always a function

    • @paulzupan3732
      @paulzupan3732 3 дня назад

      It's Haskell, the answer to any question imaginable is a function.

  • @gillchristiang
    @gillchristiang 4 года назад +147

    "that looks like something and average javascript programmer would write and is extremely lame"
    lmfao this is why I watch your videos (oh and yeah I work with JS for a living)

  • @LeoOno
    @LeoOno 4 года назад +14

    following the logical sequence of your thought to arrive at the final composite function of all predicates using monoids was amazing, very enlightening so thanks a lot :)
    !

  • @BryceTheGrand
    @BryceTheGrand 5 лет назад +73

    You could just create a function "f = (or .) . sequence"
    This is a function that when given a list of functions of type [Char -> Bool] it returns a single function of type Char -> Bool.
    This uses Monads by pulling "Char ->" outside of the list and returning a list of [Bool], which then uses "or" to see if one is true.
    Or, to get it all in one line:
    isForbidden = or . sequence [isBraille, isDigit, isUpper]

    • @dirrelito
      @dirrelito 3 года назад +3

      But that is monad. Not monoid. So it undermines the point of the video?
      ...but i agree it is the more "natural" code.

    • @micknamens8659
      @micknamens8659 2 года назад +3

      @@noomade Due to lazy evaluation the code (isForbidden = or . sequence [isBraille, isDigit, isUpper]) should work out-of-the-box (i.e. w/o compiler optimization) quite straight.

    • @maxmuller445
      @maxmuller445 Год назад +12

      @@dirrelito a monad is a monoid in the category of endofunctors. So it is still a monoid too

  • @2003vito
    @2003vito 5 лет назад +18

    Breathtaking

  • @fakt7814
    @fakt7814 4 года назад +7

    I knew about such a powerful tool as monoids before but I didn't know that any function that returns a monoid is also a monoid and it can be used in a very predictable way. Thank you.

  • @MrRedstonefreedom
    @MrRedstonefreedom Год назад +11

    If I ever pickup haskell, I saved this video since it's the fastest whirlwind tour of almost every aspect of the language environment 😂 -- in under 10 minutes!
    help system, errors, composition, libraries, it's got it all

  • @СергейКузнецов-в8ю7ш

    More Haskell videos, they are so epic!

  • @jamma246
    @jamma246 5 лет назад +4

    These are the best Haskell tutorials I've seen!

  • @nevokrien95
    @nevokrien95 8 месяцев назад +3

    This is so bizarre he changed his tune so much

  • @smuecke
    @smuecke 5 лет назад +11

    Why the hassle with importing stuff?
    isForbidden c = any $ map ($ c) [isBraille, isEmoji]

    • @Kennnn264
      @Kennnn264 4 года назад +4

      Why the map?
      isForbidden c = any ($ c) [isUpper, isDigit]

    • @bratezoran2102
      @bratezoran2102 4 года назад +4

      @@Kennnn264 why the function parameter? `isForbidden = or . () [isUpper, isAlpha] . pure`

    • @aurorazuoris6654
      @aurorazuoris6654 4 года назад +2

      isForbidden = or . sequenceA [isBraille, isEmoji]

  • @7robertodantas
    @7robertodantas 5 лет назад +4

    I've been learning a lot from you! Your videos are great! Congrats! 👏👏👏

  • @aBamieh
    @aBamieh 5 лет назад +6

    Cool, i get so excited when you post haskell content

  • @Tomyb15
    @Tomyb15 Год назад +2

    Apart from the other nice solutions or variations that have been outlined here in the comments, I wanted to mention that there is no need to fmap a newtype data constructor just to satisfy the type checker, given that newtypes are a no-op at runtime. All newtype instances are coercible with their underlying type, so you should be able to use the ```coerce``` function from Data.Coercible to turn them into Any or All with no runtime cost.
    You probably need some type signature to clarify which instance to coerce into. Something like ```(coerce :: [a -> Bool] -> [a -> Any])``` or better yet
    ```isForbidden = getAny . (fold $ coerce predicates :: Char -> Any) where ...```

  • @WilcoVerhoef
    @WilcoVerhoef 3 года назад +4

    *isForbidden c = any ($c) [ isEmoji, isBraille ]*
    I don't like importing lesser known functions when the alternative is just as concise.

  • @japrogramer
    @japrogramer 5 лет назад +15

    I used to Haskell but than I took a python to the knee.

  • @AndrewBrownK
    @AndrewBrownK 5 лет назад +39

    I think the "m" in "mempty", "mappend", and "mconcat" stands for "M"onoid

    • @WillBergson
      @WillBergson 4 года назад +11

      the thing is why it is empty and append for an identity and a binary operation

    • @arthur-vi1ub
      @arthur-vi1ub 8 месяцев назад

      That's a reference to the corresponding list operators, lists being the canonical monoid (also called the Free monoid)

  • @v01d11
    @v01d11 5 лет назад +2

    The Crazy Train mix at the end makes this video even more epic :)

  • @danielsmith5626
    @danielsmith5626 4 года назад +3

    i like how there's an efficient solution 1:25 into the video but it's scrapped for epic haskell hubris

  • @steffahn
    @steffahn 4 года назад +2

    Lol, I read the title as referring to Monads and thought you might be aiming for something like "or . sequence predicates"

  • @telnobynoyator_6183
    @telnobynoyator_6183 4 года назад +1

    *the bot took a huge coredump*
    Love it !

  • @comarnicolodi
    @comarnicolodi 4 года назад +2

    Your channel is too good to be true

  • @pdr.
    @pdr. 5 лет назад +9

    Why not just map the argument to the predicates and use "or"?

    • @jadissa3841
      @jadissa3841 5 лет назад +6

      I'd use:
      isForbidden x = any $ map ($ x) predicates

    • @asdfghyter
      @asdfghyter 5 лет назад +8

      Then you don’t get to use monoids. :P

    • @jadissa3841
      @jadissa3841 5 лет назад +3

      @@asdfghyter I've used monoids in better ways before. You should get yourself the best, clearest solution not the one that uses monoids

    • @abhishekkadam2999
      @abhishekkadam2999 5 лет назад +12

      Because, that won't be a "epic Haskell developer move" 😆😆

    • @pdr.
      @pdr. 5 лет назад

      @@jadissa3841 Yeah exactly. I meant "any" not "or".

  • @AK-vx4dy
    @AK-vx4dy 5 месяцев назад

    Respect... you really understad Monads and solid chunk of Haskell 🤯

  • @cynocephalusw
    @cynocephalusw 4 года назад +1

    „Max“ turns out to be a Join Semilattice, because it suffices idempotence.

  • @greob
    @greob 5 лет назад +40

    This is beautiful. Maybe you'd want to mention "Haskell" in the video title, for people looking for tips in Haskell specifically.

  • @aedd3307
    @aedd3307 3 года назад +1

    did u just say that ascii art uses unicode characters?

  • @sebastiangudino9377
    @sebastiangudino9377 Год назад

    Sadly this is no longer written in Haskell, he recently changed it to Go :(

  • @EduardoRFS
    @EduardoRFS 5 лет назад +3

    I will someday became an Epic haskell developer

  • @Zorgatone
    @Zorgatone 4 года назад

    Name of the outro song?

  • @gregbell2117
    @gregbell2117 5 лет назад +5

    It seems that a lot of the point of Haskell is to learn more and more abstract concepts to write code that's a little shorter, or a little weirder. I like it, but I feel that if I wrote code like this, I should probably be fired.

    • @beauteetmusculation8191
      @beauteetmusculation8191 3 года назад +2

      Actually, the examples here aren't great to understand the beauty of functional programming. In practice, the code is way shorter, and you chose if you want to make it even shorter by requiring reviewers more intimate knowledge of the language or not.

  • @PS3PCDJ
    @PS3PCDJ 3 года назад +1

    So this is how normal people feel when they see someone reason about code to implement

  • @nono1271
    @nono1271 4 года назад +1

    In JavaScript this is just
    const predicates = [isNumeric, isLower];
    const isForbidden = char => predicates.some(p => p(char));

    • @bratezoran2102
      @bratezoran2102 4 года назад +2

      ...and in haskell you can use the same concept: `isForbidden char = any (\p-> p char) [isUpper, isNumber]`.
      And then you can further simplify, which does not work in JS: `isForbidden char = any ($ char) [isUpper, isNumber]`.
      ;)

  • @davidyanceyjr
    @davidyanceyjr 4 года назад

    indeed that was a predicool video.

  • @carlost23489
    @carlost23489 5 лет назад +2

    Outstanding!!!

  • @Az181
    @Az181 4 месяца назад

    why not
    isForbidden x = and $ map ($ x) [the list of predicates]

  • @meneereenhoorn
    @meneereenhoorn 4 года назад

    Epic haskell programmer move.

  • @arisweedler4703
    @arisweedler4703 4 года назад +3

    I understand that a monoid is a function that takes type T, T as input and returns type T as output, and I understand how it is thus necessary to give a fold/reduce/whatever higher order function a monoid.
    I did not understand this at first, but a second watch cleared things up! Here is my understanding, in my own words.
    The mathematical concept of a "boolean" is clearly a monoid. But haskell is a strongly typed language! And the haskell type Bool is NOT a monoid. Luckily, there exists a class that fixes this problem. It effectively extends Bool. (Really, it wraps it, but I don't know Haskell so idk if you can extend classes. You can't in C++, you can in something like ruby. I'm being too imprecise to be nuanced here...). And it extends Bool in a way s.t. it is a monoid! So you can use it in fold.
    Thus, you need to map to wrap so you can fold then unwrap to get your answer. GG

    • @KohuGaly
      @KohuGaly 2 года назад +5

      A monoid is a mathematical object. It's a pair of set and a binary operation, that satisfies certain properties. The operation needs to be closed (ie. it always returns members of the set, when it has members as the inputs) and there's neutral element (ie. there's an element for which applying the operation to any other member, just gives back that member).
      Examples of monoids:
      Integers with addition - neutral element is 0.
      Integers with multiplication - neutral element is 1.
      lists with concatenation - neutral element is empty list.
      Boolean on its own is not a monoid, because it is not specified which operation is should be monoid to. Both logical AND and OR form a monoid over Boolean (just like integers are monoid under both addition and multiplication).
      This is where traditional OOP really sucks at expressing these concepts. It reinvents the wheel, but makes it square and puts the axis at an angle. A monoid can be thought of as a virtual class, that has one virtual field (the data type you are monoiding over) and a virtual function with two inputs and output, all of the Self class (this is the binary operation).

  • @buncha1499
    @buncha1499 4 года назад

    Your videos are gold

  • @seethruhead7119
    @seethruhead7119 4 года назад

    Really good explanation love it

  • @DanDart
    @DanDart 4 года назад

    Seems like you could continue this by explaining contravariants.

  • @DanDart
    @DanDart 5 лет назад +1

    Instinctively I'd have just gone the applicative route, so something like this:
    or $ "w" [isUpper, isLower]

    • @bratezoran2102
      @bratezoran2102 4 года назад

      @@noomade ah didn't see someone else used applicative and posted another comment. OPs code compiles, but your code doesn't. I'm curious what you did with the lambda after the `or`, haven't seen that before.
      I just know this way: `isForbidden c = or $ () [c] [isUpper, isLower]`. btw, works also without importing Control.Applicative and pointfree like so: `isForbidden = or . () [isUpper, isAlpha] . (:[])`.

    • @bratezoran2102
      @bratezoran2102 4 года назад

      @@noomade ah right, now it makes sense! the code works now. thought this was some kind of special usage of `or` with a lambda. thanks for your reply anyway.

  • @v__802
    @v__802 5 лет назад +2

    Also you can coerce predicates, so
    isForbidden = getAny.mconcat predicates where predicates = coerce [isLower,isDigit]

  • @lm1338
    @lm1338 3 года назад +39

    So this mainly shows that monoids are a really complicated way of doing extremely primitive things.

    • @kinjalbasu1999
      @kinjalbasu1999 2 года назад +14

      Please also consider the reduction in lines of code and extensibility (here, the ability to add more conditions easily).

    • @Heater-v1.0.0
      @Heater-v1.0.0 Год назад +1

      @@kinjalbasu1999 Reduction in lines of code is not a good argument. A program reduced. to a few lines of cryptic symbols and unfathomable keywords becomes as readable/understandable as a text file being zipped.
      The ability to add more conditions easily is not a good argument, we could do that with a list of functions in almost any language.

    • @thoriqadillah7780
      @thoriqadillah7780 Год назад +1

      ​@@Heater-v1.0.0well i think this monoid has been used widely in http framework, which is middleware.
      Adding more middleware easily in form of list in our handler is big

    • @Heater-v1.0.0
      @Heater-v1.0.0 Год назад

      @@thoriqadillah7780 Indeed. I think I start to get it then. This "monoid" thing is what C programmers call a a "call back". After all web servers have been allowing for the insertion of middleware since forever and I don't recall that ever being called a monoid.
      Luckily we don't need to use Haskel to make use of such a pattern. Almost any language will do.

    • @rogergalindo7318
      @rogergalindo7318 5 месяцев назад

      hmmm in a sense yes, but not really, because is the generalization of programming patterns, that allows you for easier refactorings, at least in my experience

  • @mechmaker9346
    @mechmaker9346 5 лет назад

    monoids it's good,but i don't know,how i can apply it in other situations.

  • @BrianMcKennaPuffnfresh
    @BrianMcKennaPuffnfresh 5 лет назад

    Really good stuff!!! ♥️

  • @tahamagdy4932
    @tahamagdy4932 5 лет назад

    Stunning!

  • @raphipik
    @raphipik 2 года назад

    I fucking love you! Thanks for this video!

  • @eduardoarandah9990
    @eduardoarandah9990 2 года назад

    str.includes() and you’re done. Why things have to be so complicated?

    • @sebastiangudino9377
      @sebastiangudino9377 Год назад +2

      This is a bit more complicated. Since you are actually combining functions that detect characters, not just character themselves. So while it doesn't make sense I'm this context, it will be easy to extend with mor abstract predicates (Compilers and parsers written in languages like Haskell make heavy use of this kind of things)
      So while seemingly complicated this is actually very generic and elegant! And Haskell tends to reward elegance with Maintainability and Performance increases
      But yeah, I totally get that the barrier of entry is absurdly hard. And if you have no good reason to learn Haskell I would simply not recommend it. You will speed a looooot of time with very little in return

  • @ash__borne
    @ash__borne 11 месяцев назад

    It's crazy to see that you've been doing crazy sh#t for so long 😂

  • @moy4604
    @moy4604 Год назад

    mind blowed video!

  • @stephenkamenar
    @stephenkamenar 5 лет назад +16

    that's what i call over engineering

  • @wlcrutch
    @wlcrutch Год назад

    Impressive! 👍🏻

  • @hubstrangers3450
    @hubstrangers3450 8 месяцев назад

    Thx

  • @teliph3U
    @teliph3U 5 лет назад +1

    foldMap all the things.

  • @ooloncolluphid9975
    @ooloncolluphid9975 4 года назад +1

    EPIC!

  • @ulissemini5492
    @ulissemini5492 5 лет назад +5

    you way overdid it, all you needed was
    import Data.Char
    isForbidden :: Char -> Bool
    isForbidden c = any (\f -> f c) predicates
    where predicates = [isLower, isDigit]
    or to be slightly shorter
    any ($ c) predicates

  • @blitzritz
    @blitzritz 5 лет назад +1

    Can you please do a video on Monad Transformers and Free Monads? Please! Pretty Please! You simply are the best Haskell teacher I have ever come across.

  • @random-characters4162
    @random-characters4162 Год назад

    very entertaining btw

  • @leyliramazanova4201
    @leyliramazanova4201 4 года назад

    damn, this is good

  • @DryBones111
    @DryBones111 2 года назад

    You could achieve the same result with:
    isForbidden c = any ($ c) predicates
    I'm not sure which approach I prefer however, the monoid approach is pretty cool.

  • @Nathankthanks
    @Nathankthanks 5 лет назад

    Maybe Works

  • @sergey1519
    @sergey1519 3 месяца назад

    But... Why?

  • @blocktech26
    @blocktech26 2 года назад

    fuck I love haskell

  • @bratezoran2102
    @bratezoran2102 4 года назад

    Or with Applicative: `isForbidden = or . () [isUpper, isAlpha] . pure`

  • @j22n3s
    @j22n3s 4 года назад

    Are you a magician ?

  • @Daniel_Zhu_a6f
    @Daniel_Zhu_a6f 23 дня назад

    i feel like tsoding in 2024 would not like this approach. it's good to know about monoids (for purposes of designing storage formats, algorithms, etc), but having monoid as an interface is a very dumb idea for several reasons: (1) same type can have many monoid operations, (2) it's more efficient to reduce an array of monoids at once instead of calling a binary operation on each pair of elements (3) it makes code much harder to understand bc locality of behavior is lost.

  • @alkouille2794
    @alkouille2794 5 лет назад

    ya so epicc

  • @FunkschyIsWatchingYou
    @FunkschyIsWatchingYou 5 лет назад +1

    Pog

  • @mechmaker9346
    @mechmaker9346 5 лет назад

    I love haskell vert much....
    Please...
    Make video about chat bot on haskell...

    • @123coolmik
      @123coolmik 5 лет назад +1

      Mech Maker watch the twitch live streams, he has a pre-planed schedule for them.

  • @Kennnn264
    @Kennnn264 4 года назад

    m'onoid

  • @RunningRay9
    @RunningRay9 3 года назад

    Epic

  • @DjLeonSKennedy
    @DjLeonSKennedy 5 лет назад

    Could u explain Profunctor Optics in practice ? Please!!!!!!)

  • @andreasschau4215
    @andreasschau4215 2 года назад

    Javascript script-kiddies gonna hate this trick... 😅

  • @mvmo4744
    @mvmo4744 5 лет назад

    🦄

  • @iskuchekov
    @iskuchekov 5 лет назад

    much epic such uwu! that was really cool

  • @AlexKavanagh29x
    @AlexKavanagh29x 5 лет назад +5

    I suspect this is "doing it for the sake of doing it because it is clever". "isDigit x || isUpper x" is much more readable that using the Monoid. If you really want to be "pointless" you could also do the slightly less obvious "(||) isDigit isUpper". Just because you can, doesn't necessarily mean you should.

    • @Tsoding
      @Tsoding  5 лет назад +6

      Works only with two predicates.

  • @MrRedstonefreedom
    @MrRedstonefreedom Год назад

    I appreciate the explanation, it's very cool to see! Though much the same is possible in any other language, without the needless mathematics terminological specificity.
    You maligned javascript for example, but this is a trivial implementation in javascript. Functions are objects and so you can likewise describe a "noneOfAnyOfPredicates(particular Predicates)" and simply define the predicates by virtue of a constant value type.
    Compositionality is not a new thing to uniquely Haskell, and in fact it seems quite a bit easier to express without this extra complexity baggage of "getAny" (rather misleading, and annoying boilerplate imo) or the info-doc lookups you had to do for whether haskell's arbitrary definition of boolean classified it as a monoid or not.
    Again, the video is great, it's just that one small point you made 2x was just flatout wrong. JS is not limited in this respect. In fact if anything, JS isn't limited at all, besides things like macros like you get out of lisp, but I don't think haskell has anything close to it. its problems come from the lack of limitation. or maybe with haskell, if you're doing mathematical proofs, stuff like abstract properties of the operations and maybe operator overloads though i don't really know enough about haskell to say one way or another.

    • @samuraijosh1595
      @samuraijosh1595 Год назад +1

      you have no idea what youre talking about JS kiddo

  • @newborn7348
    @newborn7348 3 года назад

    An epic USELESS move!