18 ms·
Not sure why the article has to mention monads? I mean there’s the (mathematically correct) joke that »monads are monoids in the category of endofunctors«, but
by quchen 2y ago
Not sure why the article has to mention monads? I mean there’s the (mathematically correct) joke that »monads are monoids in the category of endofunctors«, but understanding that requires getting elbow deep into category theory, and if you’re not one of the maybe 10 people in the world gifted that way has zero practical use when programming.
> A monad is a monoid over a set of curried functions.
Is that so? Sounds very wrong to me. If we want to go the monad joke way, monads have to have an operation (a -> m b) that composes, but those are just normal functions, and there’s nothing curried about it. It’s a statement that one could bend enough so it’s kind of right, but what it really does is raise eyebrows.
> Monads force sequential processing because you set up a pipeline and the earlier stages of the pipeline naturally must run first.
No, a counterexample is the (esoteric) reverse state monad, where values flow the normal way but state comes from the results of future computations.
- tpoacher 2y agoI found it useful to have them mentioned, since people new to this topic (or, e.g., Haskell) tend to bump onto monoids when they first try to understand monads. A 'handwavy' association that somewhat makes sense and allows you to have some sort of perspective when moving on to monads is better than simply omitting the link to monads completely, just because one can "kindof maybe" find holes in the simplified explanation provided. (fair enough, the words "this is somewhat oversimplified, but" could have been added, but personally I didn't care)
- marcosdumay 2y ago> tend to bump onto monoids when they first try to understand monads That's unfortunate. They should be bumping onto monoids much earlier, and much more often. Yeah, IO and do notation put monads on the face of people way before they have time to adapt to it. But monoids are the one that are extremely valuable, simple, and easy to learn. Also, they make for a nice step in a progressive adaptation to the "generalized thinking" one need to understand why Haskell does the things it does.
- recursive 2y agoWhy? Serious question, but what's the use of monoids? I encountered the term years ago, when I had an ill-fated ambition to make sense of monads. I've let it go and made peace with the world. But outside that narrow context, I've never even heard the term "monoid". What are people using it for in the real world?
- TuringTest 2y agoAs the article explains, fold functions are a simpler way to think about monoids. So in recursive pure functional programming, many important iterative processes (pipelines, accumulators, machine states...) can be expressed as an application of fold-l or fold-r.
- ndriscoll 2y agoRoughly, something is a monoid exactly when a parallel reduce type of algorithm can be used. The associativity lets you break it into sub-problems, and the unit lets you insert padding where necessary to get same-sized blocks for parallel processors. It's also a useful concept to know for library design. e.g. when there's a "combine" or "reduce" operation on some data type, it should occur to you that your users will probably want a neutral "do-nothing" element and that your operation should give you a monoid. APIs without one are usually annoying to work with and require extra if statements/special casing. More generically, named concepts like this give you a way to compress knowledge, which makes it easier to learn new things in the future. You get comfortable with the idea of a monoid, and when you meet a new one in the future, you immediately have an intuitive ground to build on to understand how your new thing behaves.
- recursive 2y agoThanks. Parallelization of T[] => T operations makes a lot of sense. Monoids seem to introduce exactly the necessary constraint to allow some kinds of operation re-ordering needed for various perf optimizations like parallelization. I get it!
- epolanski 2y agoIt's kind of natural that you need to progress from a magma/semi group monoid (algebra) to functors/applicative/monad (category theory) Would it help if you defined a monoid as a combination of 3 things? 1) a data type A 2) an associative operation on A 3) an identity (or empty element) Then you can correctly say that the string data type, admits an associative operation (concatenation of two strings) and you have an empty element (the empty string). I think too many people talking about functional programming really overblow how much you need to understand about mathematics, they serious do. Think about my definition and you can quickly understand that there are many monoid instances for numbers (with the associative operation being addition to get a monoid or multiplication to get another monoid instance). There's infinite numbers of monoid instances for various data types. Haskell has several shortcomings from what I remember and Haskell developers incorrectly assume that you can only have one semi group (or equality, monoid, etc) instances for your data type because they believe they are the closest to math, but in reality their language has its own limitations.
- marcosdumay 2y ago> Haskell developers incorrectly assume that you can only have one semi group (or equality, monoid, etc) instances for your data type They don't assume that. The devs bent the compiler backwards several times trying to support more than one instance, but they still couldn't design an implementation that is actually good to use. If you know of any language where this works well, it would be nice to know. AFAIK, representing that kind of thing is an open problem, nobody has an answer.
- quchen 2y agoI think Idris addresses this fairly well, if there's more than one instance (and the code is ambiguous) you have to annotate which one.
- ndriscoll 2y agoScala does it well. Implicits make it easy to pass along the instance you mean. You can put a default on the companion object if you want, but you can override where needed. Implicits on the companion object have lower priority than those in current scope.
- lambdas 2y ago> Is that so? Sounds very wrong to me. If we want to go the monad joke way, monads have to have an operation (a -> m b) that composes, but those are just normal functions, and there’s nothing curried about it. It’s a statement that one could bend enough so it’s kind of right, but what it really does is raise eyebrows. I can see where they’re coming from, but they certainly haven’t set the stage for it to be a something you could deduce without already knowing what they’re referencing. So to me, it seems they’re referencing the Free Monad, recursion schemes and a little of HomFunctor/Yoneda Lemma. The free monad gives a coproduct of functions, where the value is either a recursive call or a value (branch vs node). To get from a set to a free monad, you need to define a Functor over the set, and given most things are representable, this is trivial. Given this free monad, an algebra can be formed over it by providing a catamorphism, where the binary function would indeed be composition.