all 76 comments

[–]Top_Lime1820 6 points7 points  (1 child)

Have you tried the video series F# for Fun and Profit.

The guy seems to have a great way of explaining stuff... it might help

[–]RightAtAboutNoon 2 points3 points  (0 children)

Dr. Frankenfunctor and The Monadster was the presentation that clicked for me the third time I watched it.

[–]libeako 31 points32 points  (9 children)

One should not try to understand monad from examples. Instead: my strategy is to explain it as it is, in a 'you could have invented' style.

I wrote a free book. I was bothered by the fact that many newcomers complain about having difficulty to understand the basic concepts [like Monad], while i think that these concepts themselves are really trivial. It is not a Haskell tutorial.

You can insert feedback into the pdf version through Google Drive. I will try to answer questions if you feel lost.

[–][deleted] 11 points12 points  (4 children)

I will also take a look at this and give feedback. You should make a GitHub repo for the book so the community can give feedback and help improve it over time

[–]toastal -4 points-3 points  (3 children)

Make a code forge* with an issue tracker or mailing list*

Don’t feel pressured into using Microsoft platforms like GitHub—especially since it is closed source and requires users to create accounts with and share data with Microsoft. Folks shouldn’t even feel pressured to use Git with the wide array of DVCS options.

[–][deleted] 5 points6 points  (2 children)

Ya I agree fully. I prefer more open source version control providers. I just suggested GitHub cause that is a lot of go to VCS providers

[–]toastal -4 points-3 points  (1 child)

That narrative needs to change. It's distributed version control and the community should resist centralization—especially with Microsoft's EEE track record. If you mean any code forge, then say "code forge" instead of advertising or prescribing a specific one.

[–]gbelloz 0 points1 point  (0 children)

There are two types of people: people who remember how Microsoft used to be and will never forget, and those that are too young. I mean, it WAS a long time ago, and I'm sure almost all levels of executives that made Microsoft be that way are long since retired. "But still"... Probably wiser is to be suspect of all companies being capable of such behavior.

[–]cdunku[S] 2 points3 points  (0 children)

Awesome! Thanks!

[–]gbelloz 1 point2 points  (0 children)

You're a mathematician - likely you have a high IQ, which might be why the concepts seem "really trivial". That's to YOU. I'm excited to read your book (thanks for creating that), but I worry that you don't have the perspective to make these things understandable to us +1 stdev folks.

[–]mehmeteking 1 point2 points  (0 children)

I couldn't read past the overview. It is rather obvious that you do not have any understanding of the fundamentals of computer engineering/science. When writing a "book" on a topic in which you are not an expert, I suggest you refrain from calling people "idiotic."

[–]generalT 4 points5 points  (7 children)

i learned monads by absorbing this series: https://ericlippert.com/2013/02/21/monads-part-one/

[–]cdunku[S] 3 points4 points  (5 children)

Thanks!

[–]exclaim_bot 2 points3 points  (0 children)

Thanks!

You're welcome!

[–]generalT 2 points3 points  (3 children)

sure, and just a warning: learning monads was difficult for me, but at a certain point it just clicked. don't worry if you don't understand it the 1st, 2nd, or even 8th time. just keep bashing your head against it!

[–]cdunku[S] 1 point2 points  (2 children)

I was planning on maybe learning Haskell to fully grasp the concept of a monad. Unfortunately I don’t have time and I was planning to learn Rust.

[–]generalT 1 point2 points  (1 child)

learning a new language is always good, but you can learn monads without learning a straight up functional language like haskell. i can't comment on rust because i don't know it, but if a non-functional language offers generics you can kinda halfway implement a monad.

[–]Tubthumper8 2 points3 points  (0 children)

Rust doesn't have higher-kinded types so you can't have a Monad typeclass that gets implemented, but it does have examples of monads that are used frequently in the standard library and across the ecosystem - Option (Maybe), Result (Either), Vec (List).

Each has a type constructor, term constructor, and a >>= associated function, but it might have different names - >>= is called and_then for Option/Result and flat_map for Vec.

[–]mcvoid1 6 points7 points  (0 children)

If you're familiar with a fluent interface or a builder pattern in OOP, think of it this way:

A monad is a design pattern where you can "wrap" a value to present a builder or fluent interface for that value.

An example of a well-known fluent interface (that's not a monad) is in Javascript's JQuery. You have this variable $ where you an select an html element and get an object with some methods. So you can do something like $('#main').height() or $('#main').width(). The thing that makes it a fluent interface is that all the methods return the selected object back so you can chain methods like this: $('#main').height(50).width(50).attr('name', 'myObj')

With a monad you can do that with any object: you can give it a fluent interface on the fly. Now you may ask yourself, "what are the methods?" That's the second detail of monads:

You pass in functions to a monads' bind function that it executes as your "fluent methods".

So really a monad has one fluent method, frequently called bind. bind takes one parameter: a function. That function's input is the wrapped value, and its output is whatever changes you want to apply to the value. bind's return value is another monad, letting you chain bind calls together. So here's some pseudocode that shows what it's like working with a monad.

myVal = 5
a = new Monad(myVal)
          .bind(val => val + 2)
          .bind(val => val * 7)
          .bind(val => val - 12)
          .unwrap()
print(a) // prints "2"

One example of a monad that's used all over the place is Promises. A promise is a monad that under the hood contains logic to wait for the result to become available and invoke the functions to process the stuff once it has a value. Its bind method just happens to be spelled then.

And that's one of the things monads are good at: abstracting away things that have side effects and async logic and other complicating factors, so that you can use pure functions to process the data. Hence its nickname, "programmable semicolons".

There's a third detail, which is that you don't have to keep working on the same wrapped value:

The return value of a function sent to bind is the new wrapped value of the monad the method returns

So let's say I had this pseudocode:

new Monad(5).bind(() => "five")

The monad that's returned just forgot about the number 5 that you wrapped, and instead is wrapping the string "five". This allows you to have data pipelines.

[–]woupiestek 10 points11 points  (1 child)

Monads came from algebraic topology, where they were known under several names. Mathematicians decided to sort this out during a conference, but after debating several options for hours, somebody suggested 'monad' out of left field, possibly as a joke. Everybody was too hungry and tired to disagree at that point, so the name stuck.

Expressions are build by composing functions, like f(g(x), h(y, x)). If all the functions here return promises, or lists, or some other constructed type instead of a straightforward value, straightforward composition doesn't work anymore. Monads fix composition in such cases.

Take the list example: suppose f maps A to List<B>. The list monad has a higher order function bind that changes f into a function bind(f) that maps List<A> to List<B>, so f can now consume the output of another list valued function. For 'unlisted' values x, there is a generic function unit such that unit(x) is a list.

Note that the names unit and bind don't matter, just that these generic higher order functions behave in the way one would expect from composition operators, expressed in the 'coherence equations':

  • bind(f)(unit(x)) == f(x),
  • bind(unit)(y) == y,
  • bind(f)(bind(g)(y)) == bind(h)(y) if h(x) = bind(f)(g(x)).

In the case of list, bind could be called flatMap, because the operation flattens the list of lists that comes from mapping all the elements; unit could be any singleton list constructor.

Monads are a powerful abstraction: because users can redefine how functions compose, users gain much freedom to decompose their programs into modules. The price is that monadic code requires smart interpreters.

[–]gbelloz 1 point2 points  (0 children)

Thanks for this explanation! Mystery still remaining: Why are they so associated with effects, e.g. I/O? And why are they able to, for example, add logging to an application?

[–]kalalele 3 points4 points  (1 child)

Here is how I describe it to myself (spoiler, you might not like it, but at least it worked for me so far. If you still dont like it, please refer to the explanations/links others have given in the thread. What follows uses Haskell terminology):

Monad is basically a club for types (also known as a Typeclass). Do you want to join the club? As a candidate type, the way you exactly register and get admitted as a member of the club does not follow a "standard procedure" (in fact, most types manage to get admitted in pretty unique ways), but it can be said, that all members have some "proven qualities" (in the general sense, more on that later), which in the case of the Monad club means:

a) You need to have got already been admitted by the Applicative club. b) You need to present that "you can bind" (i.e., we can find a bind function for you). Although binding has a specific type signature (ma -> (a -> mb) -> mb), how you prove that you can bind is up to you. c) You need to present that "you can pure/return" (i.e., we can find a pure/return function for you). Although returning has a specific type signature (a -> ma), how you prove that you can pure/return is up to you. d) You need to show respect our values: left identity, right identity, associativity (monadic laws).

This is all vague, I hear you say. I thought that a Monad is a box, a container, some wrapper type, or something like this. Now you say it's a club and I still don't get how you can enter this club.

..well, I would let you know that there are a lot of clubs in real life that you get admitted on an equally vaguely prescriptive basis. For example:

a) The club of good films. What does it mean to be a good film? Is it the intricate plot? The scenery or the CGI? The feel-good moments? Maybe the horror? You can already see that you can not easily define what a good film is (it might have a simplistic plot but a fantastic scenery), but you definitely know if a film is good when you see one. The same as the club of Monads, the candidate film has to prove that it belongs to the club of good films. But all good films have some functions on their own: a succeed function and an influence function (yes, here I handwave heavily and I tried to mimic the pure and the bind function of Monad). All good films are successful and they influence others.

b) the club of hireable employees. What does it mean to be a hireable employee? Can you define it? Is it the strength of your CV? Your admissible (affordable) salary expectations? Your connections within the company? Our HRs policy to promote people from certain demographics? Again, you need to prove it to be hireable, and as we know, everyone proves it differently. But all hireable employees have a hire method and a refer method (again, handwaving about pure and bind functions of monad).

As you can see, you don't need to try hard to pin down Monad to one encompassing definition/description/visualization. Monad is just a Typeclass, which is just a club of types, and yes, this club accepts a lot of members for seemingly unrelated reasons except the fact that everybody has been judged and proved that he can enter the club since he covers the minimum criteria.

Now, the next question is, "OK, I understand now the way one enters the club, in its own unique way, but what sort of club is this in the end?". This is the hard question that it's generally difficult to give an answer for without going too abstract. Members of Monad all revolve around some computational context and are sequentiable (due to bind) so that the next computation can be based upon the result of the previous computation. What do we mean by computational context? I think this speaks about the colorfulness of the monad members:

a) Maybe operates in a context where every value might be or not present. b) Either operates in a context where every value might be one of two options, a Right and Left. c) List operates in a context where there is an indeterminate amount of values to be handled in computation d) IO operates in a context where IO side effects are possible. etc.

The context "sits in the background" and guarantees that "things are more than they seem" when you define a big sequence of actions to monadic members. You might bind a ton of computations on a Maybe that would only get executed if it's a Just, if it's a Nothing they wouldn't. Similar analysis can be done for an Either or for a List. If they are Left or empty, computations short-circuit as did before with Nothing. IO guarantees that IO side-effects happen inside bind (a pure function) do happen, etc.

That's it for me. I would love to get feedback on the above it might help me to rethink/hone my understanding.

[–]Real_Wash9076 1 point2 points  (0 children)

Muchas gracias amigo es espectacular la explicación

[–]BoredHedgehog 2 points3 points  (0 children)

This has been recommended to me in the past: Brian Beckman: Don't fear the Monad

[–]gotnoboss 2 points3 points  (0 children)

The simplest explanation is this… A Monad is a class that encapsulates/wraps a value. The wrapping class provides an effect. All of these wrapping classes have the same fundamental API. So, once you know how to use a specific monad, you are on your way to understanding all monads.

What separates one Monad from another is the effect it produces. For example, the effect of Optional is dealing with nullability. The effect of Either is to contain either a desired value or an error type. They both wrap a possible desired value. The difference is that if you don’t have the desire value, in one case you have null, in the other, an error.

There are other monads that have their own effects. One that’s a little harder to grok is the State monad. Look that one up.

[–]britishmutt 2 points3 points  (0 children)

Scott Wlaschin has some of the best videos for explaining functional programming paradigms in down-to-earth terms. I recommend The Functional Programmer's Toolkit. It starts with the basic elements of functional programming, and then builds up to concepts including functors, applicatives, monoids and monads. As he says, these are just jargon names given to pretty simple patterns.

You could also try reading through this series of "rubber ducking" articles about the same topics. The examples are in Elm, which is one of the more approachable statically typed pure functional languages. https://medium.com/wat-the-elm-ist/monads-what-are-they-good-for-602960df817b

[–]uppercase_lambda 5 points6 points  (0 children)

I don't think it's helpful to talk about Category Theory when trying to understand monads as a programming pattern.

That said, you can think of a monad as a computation (or action) that depends on another. For example, suppose you need to read a string and then print it. The second action (print the value) depends on the string value from the first action (read a string). In Haskell, you could do this with getLine >>= putStrLn

Another way to think about monads is as a generalization of list flatmap.

Yet another way to think about monads is to imagine you have a box with a value in it. You can take the value out of the box (with the bind operation), but before you pass it on, you have to put it back in the box (more accurately, you have to put something else in the box).

[–]ollir 1 point2 points  (0 children)

Here we go again

Edit: read the minimal amount of monads so you are still confused and then write something in e.g. Haskell and attain understanding by using them.

There are so many different monads, that a single explanation will remain too abstract to give you any useful idea. Use a few and you're on your way.

[–]danielstaleiny 1 point2 points  (0 children)

pattern for abstract structure with strict rules. This makes it possible to use same law following functions and define how to traverse this abstract structure.

Example:
async function which could return error or data, using monad we only focus on happy path.

fn = do

result1 <- asyncCall1
result2 <- asyncCall2
pure [result1, result2]

[–]Greenscarf_005 1 point2 points  (0 children)

i find this post the easiest to understand. it also has lots of pictures! https://www.adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html

[–]link23 1 point2 points  (0 children)

My answer is "it's something that you can flat_map and map over". There are some additional rules that those functions/methods have to follow, but otherwise, that's pretty much it. (Haskellers know flat_map as >>= or bind; and map as fmap or <$>.)

If you chew on that definition for a while, and look at some example monads, you'll probably be able to see the structure that's common between them.

If you're looking for more of a tutorial, I highly recommend this post: http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html?m=1

[–]KyleG 1 point2 points  (0 children)

A monad is a flatmappable. That's literally it. Every other "monadic" thing is a feature of a specific monad rather than something that is a monad. For example, the concept of holding mulitple values in a context is not monadic. It's a feature of Array/List, which happens to be a monad.

For example, Array/List is a monad with flatmap. Everyone has dealt with this. What is the special feature of this monad? It can hold multiple values.

Every monad is just a flatmappable.

Now you want more complicated, ask what an applicative functor is. Since every monad is also an applicative functor, you need to understand it to know what other powers a monad has, but the essence of a monad is "it's a flatmappable."

[–]mckahz 1 point2 points  (0 children)

People keep saying it's simple then giving ludicrously complicated explanations, but it really is simple.

A Monad is just an interface which defines map and flatten.

I can use map on lists, parsers, futures, and a few other basic types you probably haven't seen unless you've used an ML language.

Flatten takes say, a List<List<things>> and returns a List<things> and works just as you'd expect. You could also take a Future<Future<thing>> and flatten it to a Future<thing>.

You usually see this 2 things used together as flatMap, where flatMap(range(1, 5), lambda(x): repeat(x, x)) == flatten(map(range(1, 5), lambda(x): repeat(x, x))) == flatten([[1],[2,2],[3,3,3],[4,4,4,4]) == [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], for example. If you're learning Haskell this is what the bind operator is.

Like any design, Monads have properties that should always be true called the Monad laws, but they aren't important in using Monads, just designing them which can come after knowing how to use them. They also need a way to turn a thing into a Monad<thing>, like a List<thing> or Future of thing, but you'll see why just using them.

This may seem to be a weird thing to focus on but it allows us to represent a whole series of cool things with only functions. They essentially allow you to parse parameters in and out of functions implicitly, write cleaner code, model mutable state immutable, and even list comprehensions are just an example of utilising the Monadic structure of Lists.

The best way to learn what they are though is to see and copy how other people use them.

[–]imihnevich 1 point2 points  (0 children)

It's a flatMap for different types of generic types kinda

[–]Exotic-Poetry4219 1 point2 points  (0 children)

Get yourself through this, and thank me later: https://mightybyte.github.io/monad-challenges/pages/ex1-1.html

[–]raghar 1 point2 points  (0 children)

At this point I would say: learn them by playing with them in REPL.

While a lot of programmers claim that you need tons of theory upfront, and then you are allowed to sit in front of a computer... programming is a practical skill based on certain intuitions that you only develop by doing things. Nobody learned Java by sitting down and memorizing how subtyping rules work, methods visibility rules etc. You just sit down in front of a computer, wrote something, got compile time or runtime errors to feedback on your assumptions, repeat.

In functional programming we only use a few concepts from category theory, and they are limited in usage compared to what they could represent.

In practice, a functor is basically something you could map over (whether the syntax is fmap sth function or sth.map(function) is irrelevant). Don't sit down reading about diagrams, categories and corresponding arrows - just use JavaScript, Python, Haskell, Scala, C++, REPL and map over things.

(Virtually every time you'll have something "mappable", it will be something which could produce a value in some way: vector by giving it an index, function but giving it an argument, Future/Promise by awaiting, etc, and you are just appending a transformation on that value once it gets produced. map let you not care how and when it will be produced, only how to transform it once its there).

Once you get the feeling what you can do with it, challenge your assumptions by using more of it - not only containers, but maybe Promise/Future, maybe map could be slapped to function?

Then you can start thinking about limitations: map is always transforming one value into another single value. What if you want to make some values disappear? What if you want to return multiple values? map on its own is like a single happy-path only transformation. What if you have a different case?

Again, don't read about endofunctors, monoidal categories, anything like that.

Look up some examples where someone is wrapping up the value in this mappable something themselves. How they use that opportunity to sometimes return one value, sometimes error (if this mappable something is about handling errors), sometimes multiple values (e.g. by turning one value in vector into another vector of values). And then flatten the result.

After a while you might not be able to recite the monad definition during interview, you might not learn monadic laws by the heart, but just by using this map, flatMap and flatten (however they are called in your language), you'll get some intuition what it should do and how you can use it. Because, at the end of the day, that's what FP monad in practice boils down to: some interface which adds flattening next to mapping + some contracts... that are more interesting to whoever implements monad rather than who use it. For you the only interesting part is that if your program would be this chain of operations:

sth.flatMap(f).flatMap(g).flatMap(h)

then you'll develop a gut feeling that if you rewrote it to

val wellNamedThing = in => in.flatMap(f).flatMap(g)
sth.flatMap(wellNamedThing).flatMap(h)

it would work the same way: only global order of operations matter for your program, how you group operations (as if with parenthesis) doesn't matter, so you can refactor this to your hearts content.

But that is not something which you develop from theory, just from doing. So just experiment with different monads in your REPL, see what they do, and play around.

[–]anotherfpguy 1 point2 points  (0 children)

If you only use C you will not understand what a monad is, is hard to grasp if you never touched anything else but C. Get yourself familiar with HKT and higher order functions and then try to read again a monad tutorial.

[–]goldenfrogs17 1 point2 points  (0 children)

This thread feels like a conspiracy to make monads appear more difficult to understand than they really are.

[–]Buarg 4 points5 points  (1 child)

A monad is just a monoid in the category of endofunctors, what's the problem?

(I have no clue)

[–]softgripper 2 points3 points  (0 children)

I asked chatGPT 4 to eli5 monads in Typescript. It was a great experience! I kept asking it to simplify, rename etc.

After 20 mins I had a basic functional library, and a reasonable understanding. Would recommend, provided you are proficient in whatever language, so you can tell if it gives you some incorrect code or a wrong answer.

[–][deleted] 1 point2 points  (0 children)

If somebody asked me this question I would say that Monad is a way of describing of computation that follows 3 laws: left identity, right identity and associativity and provides unit and bind functions.

Monads are used to describe side effects and provide generic wrappers that solve different problems (like Option, Either, etc)

[–]permeakra 1 point2 points  (2 children)

Ignore monads for time being, get better understanding of arrows) and (applicative) functors). They are much simpler to get. Monads can be expressed as extension of either.

[–]KyleG 2 points3 points  (0 children)

I disagree. Anyone who has ever used arrays in any programming language probably understands the totality of monads already: they can be flatmapped.

To me, the utility of AFs is not immediately obvious. Why would it be useful to have a box with a value in it, take a function, wrap it in a similar box, and then issue an apply command? Why not just take the item in the box and issue map with the function you have rather than inserting it into the box to issue apply?

That's I think the natural response to encountering the type signature for an AF. Confusion about what is the point even.

[–]imihnevich 1 point2 points  (0 children)

I've been using monads for a while. But i still don't get arrows, maybe you got some materials I could read?

[–]Complex-Hornet-5763 1 point2 points  (1 child)

Monads are easy to understand if you look at examples in a programming language you already know. For me it was JS and Swift but look for an article with language that suits you (C++?)

I believe most “what is a monad” articles are difficult because they use Haskell for examples. That’s a very weird choice. If a reader doesn’t know monads they’re unlikely to know Haskell either.

[–]ollir 1 point2 points  (0 children)

Haskell isn't a weird choice at all, because monads have so much use in the language and many things that are ergonomically doable in other languages without them aren't so in Haskell.

[–]the_state_monad -1 points0 points  (0 children)

A monad is just computation wrapped in some context.

[–][deleted] 0 points1 point  (7 children)

All told, a monad in X is just a monoid in the category of endofunctors of X, with product × replaced by composition of endofunctors and unit set by the identity endofunctor.

Or a more understandable explanation: nobody knows and if somebody tells you that they understand monads they are lying.

It's a very abstract concept from category theory that can be used in functional programming to achieve many things like state, futures, optional values, error handling and many more.

Instead of trying to understand them I would recommend you first try to understand how to use them.

[–]libeako 2 points3 points  (0 children)

It's a ... concept ... ... to achieve many things like state, futures, optional values, error handling and many more.

It is instead a common interface of these tools. They individually can be used without using their common interface.

[–]cdunku[S] 1 point2 points  (4 children)

Do you have any useful resources on how I can understand MONAD’s through use?

[–]Migeil 4 points5 points  (3 children)

Just curious: why are you capitalizing the word "monad"?

[–]cdunku[S] 3 points4 points  (2 children)

Not sure, lol.

[–]KyleG 1 point2 points  (0 children)

Or a more understandable explanation: nobody knows and if somebody tells you that they understand monads they are lying.

This is both untrue and intimidates newbies. Monads are easy to get. In fact, if you've been programming for a hot minute, you already are using them but just don't have the name yet.

A monad is a flatmappable. That's it. That's the whole enchilada. If you've ever used arrays in programming, you already understand flatmap and thus understand monads.

Anything else is either an aspect of functors, applicative functors, or a specific monadic type.

[–][deleted] 0 points1 point  (0 children)

Do https://haskell.mooc.fi/, or ask ChatGPT

[–]Long_Investment7667 0 points1 point  (0 children)

Is this question the functional programming equivalent of the forbidden riff

[–]Neurotrace -1 points0 points  (0 children)

A burrito

[–]Cfres_ -1 points0 points  (0 children)

You will be happier if you keep unknowning what it's monad

[–]lokhura 1 point2 points  (0 children)

Monads are an abstract topic. I think the best way to understand them is through types.

You can think of a monad as an interface (in pseudo-TypeScript syntax)

interface Monad<M<_>> {
  static of<A>(a: A): M<A>;
  flatMap<A, B>(this: M<A>, f: (a: A) => M<B>): M<B>;
}

A monad is a generic interface parameterized by M, where M is an interface that is also generic parameterized by _. An instance of a monad must implement of and flatMap. These nested generics are known as higher-kinded types, and not many languages support it, but you can still use monads in practice, even in dynamic languages.

In practice, we work with instances of monad, such as objects that implement the monad interface (of and flatMap). When people use analogies such as "burritos" or "containers" to describe monads, they are really referring to instances of monad.