Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Blog post that explains Functors, Applicatives, And Monads in pictures http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...


This blog post may help some but readers shouldn't expect it to magically flick a switch that allows them to use or create monads.

Instead, I really like:

1. Stephen Diehl's “Eightfold Path to Monad Satori” from “What I Wish I Knew When Learning Haskell”:

http://dev.stephendiehl.com/hask/#monads

“Much ink has been spilled waxing lyrical about the supposed mystique of monads. Instead, I suggest a path to enlightenment:

1. Don't read the monad tutorials. 2. No really, don't read the monad tutorials. 3. Learn about Haskell types. 4. Learn what a typeclass is. 5. Read the Typeclassopedia. 6. Read the monad definitions. 7. Use monads in real code. 8. Don't write monad-analogy tutorials.

In other words, the only path to understanding monads is to read the fine source, fire up GHC, and write some code. Analogies and metaphors will not lead to understanding.”

2. Chris/kqr's “The ‘What Are Monads?’ Fallacy?”, which mirrors the advice from Stephen Diehl:

https://two-wrongs.com/the-what-are-monads-fallacy

“Instead, learn to use specific monads. Learn how Maybe a works, learn how Either e a works. Learn how IO a and [a] and r -> a works. Those are all monads. Learn to use them with the >>= operator and with do notation.

Once you've learned how to work with all of those, you'll have a really good idea of how monads can be used.

Asking "What is a monad?" to learn how to use monads is as wrong as asking "What is a musical instrument?" to learn how to play musical instruments. It's a good start, but it won't teach you very much.”


Eric Lippert's blog series on Monads[1] follows this approach and is very effective in teaching the concepts behind Monads. He starts out with standard concepts from C# that are Monads and shows how they're implemented and what they have in common. It is very approachable for an object-oriented programmer who's curious about functional programming.

1: https://ericlippert.com/2013/02/21/monads-part-one/


> Asking "What is a monad?" to learn how to use monads is as wrong as asking "What is a musical instrument?" to learn how to play musical instruments. It's a good start, but it won't teach you very much.”

Another good analogy might be learning circular breathing for ordinary everyday conversation.

You might hear the circular breathing is an amazing thing that allows you to do things you couldn't otherwise do. If you are trying to use that trick without ever learning to play an instrument then there will be a great air of mystery to it all.

Monads solve problems that are only made apparent by other design decisions in Haskell. In a non-functional, loosely typed context they are not so useful.


Yes, I didn't include the papers below in my parent response because, “just read these dense academic papers to understand what monads are and why Haskell has them” doesn't tend to be good advice for Haskell beginners. But learning why monads came to be included in Haskell is useful if you want to dive deeper into this stuff:

Philip Wadler's original paper on Comprehending Monads [PDF]: https://ncatlab.org/nlab/files/WadlerMonads.pdf

Philip Wadler and Simon Peyton-Jones' paper on Imperative Functional Programming [PDF]: https://www.microsoft.com/en-us/research/wp-content/uploads/...

Simon Peyton-Jones mentions both papers and talks about why monads came to be part of Haskell in his talk on the history of Haskell here, with examples that are a little more accessible than the above papers: https://www.youtube.com/watch?v=re96UgMk6GQ [introduction to purity and then monads starts around 30:07]

It's a funny talk and it's worth watching in full, but here's a nice soundbite:

“So what did we do for IO? Well, we just didn't have any. [audience laughs] So the joy of being an academic, right, is you can design a language — in 1990, I beg to inform you — that had no input/output. A Haskell program was simply a function from string to string. That was what it was. … But this was a bit embarrassing…”

He goes on to talk about other ideas they explored to create effects, why they settled on monads, and why he wishes now they had called them something like “workflows” (as F# later did[1]) to make them sound less intimidating.

(Simon and Philip will both be at Haskell Exchange 2019 in London this coming week if anyone else, like me, enjoys spending two days as the dumbest person in the room: https://skillsmatter.com/conferences/11741-haskell-exchange-... )

[1]: https://blogs.msdn.microsoft.com/doriancorompt/2012/05/25/7-...


> Monads solve problems that are only made apparent by other design decisions in Haskell. In a non-functional, loosely typed context they are not so useful.

This is key. I've tried to write a "Monads in JavaScript" article many times over the years, but it's pointless, because you have to preface it with 100 imaginary constraints.


idk, rxjs, observables, and promises seem pretty popular. Doesn't mean it makes sense to try to write all your js code in an fp style though.


Sure they're popular, but the reason they don't talk about monads, even if they are monads in an abstract sense, is that in those problem domains the abstraction doesn't bring any clarity to the design.


Whether they talk about it or not, monads did inform their design. rxjs literally has methods named `flatmap`


> Asking "What is a monad?" to learn how to use monads is as wrong as asking "What is a musical instrument?" to learn how to play musical instruments. It's a good start, but it won't teach you very much.”

This is such a great analogy!


Condescending tutorials seem to be an integrated part of Haskell culture. The rationale might be that people who don't already know Haskell should to talked to like kids. "Don't be scared, a monad is just like a Burrito!" and so on.

I can't recollect I have ever learned a programming concept through metaphors. The only way I have learned concepts is though solving tasks in a language and thereby learning to use the tools available.

I actually think Haskell is a very enjoyable language, but there is a culture around it which treats the type concepts (arrows, monads etc.) like goals in themselves rather than tools to achieve something useful.


The only condescension I see in Haskell-related discussion is condescension towards Haskellers, claiming that Haskellers are condescending and say condescending things like writing condescending tutorials.

As I see it it’s actually not very nice.

With the utmost respect, truly, humbly: I am against this custom that it’s just fine to call well-meaning people for condescending. As it appears to me, claiming condescendence is more of a statement of the claimant, but this is still an unfortunate custom. Who are we really to claim condescension? Really?

The article linked to in the post starts off with quotes from people who directly state that they feel like they would need to be smarter to use Haskell. It’s a common thing. The article addresses that. It is literally the opposite of condescension.

Then there’s the burrito tutorials with pictures. I for one actually think in weird abstract sloppy metaphors and colors. My head really is full of burritos and inaccuracies. I was helped enormously by the burrito concept. Textbooks generally don’t speak in burritos. I work with people to whom the burrito class of analogies is not helpful. They think in a more direct and crystalline way. I wish I were more like them. And I try try to be. And I can. And it makes me better. And I really do think I also bring something to the table by spraying flaming burrito concepts and lateral jumps into the team zeitgeist.


> I was helped enormously by the burrito concept.

OK fair enough, I can only speak for myself and the way I learn concepts. The way I learn a new language or platform is always to try to write a real program that does something. I am only able to lean concepts when I can see their usefulness. But I should recognize that other people learn in different ways.


I want to add that I actually do see how it comes across as condescending. After this exchange and thinking about what you wrote. idk, like, “Here, look at these kiddie pictures, those are suitable for you, and then I’ll withhold the real work ok?”


> My head really is full of burritos

Not such a bad life, if you ask me.


   The only condescension I see in Haskell-related discussion is condescension towards Haskellers, 
fwiw I've heard exactly the same claims by and about lispers.


And sometimes justified too. But in a different way. You don't see lispers ensuring us "You are smart enough to learn Lisp" because Lisp is quite easy to get started with. And you don't usually see lispers trying to be "friendly" by communicating in children's language.



I was wrong. And that book even looks interesting!



> Condescending tutorials seem to be an integrated part of Haskell culture.

Could you perhaps link to one? I know of plenty of misguided tutorials that try to be helpful but aren't. I've never come across one I'd call "condescending".

> I can't recollect I have ever learned a programming concept through metaphors. The only way I have learned concepts is though solving tasks in a language and thereby learning to use the tools available.

Yet for some reason newcomers (reputedly) want to know what a monad is before trying to use one! I agree with you: they should go ahead and use one and not worry about what it is!


It's not unique to Haskell, and I wouldn't say condescending. More like patronizing and a little infantile. 'Learn you a Haskell' is in the same tone.

Ultimately most of these are just imitations of the 'poignant guide to ruby' which is probably responsible for starting the trend of whimsical and zany programming guides.


You need to use the IO monad to write "hello world". So it is naturally the first question a newcomer will ask. But for example "Learn you a Haskell" http://learnyouahaskell.com/chapters postpones "hello world" to chapter 9, after explaining things like type classes. So the reader is expected to read and understand 9 chapters before writing the first program? This is ridiculous - I certainly wouldn't be able to learn anything that way.


Sure you need to use the IO monad to write "hello world" but you don't need to understand what it does in the background.

  #include <stdio.h>
  int main(int argc, char *argv[]) {
    printf("Hello World!\n"); 
    return 0;
  }

  class HelloWorld {
    static public void main(String args[]) {
      System.out.println("Hello World!");
    }
  }

  main :: IO ()
  main = print "hello world"
Hello worlds in C, Java and Haskell. I can write them and run them without needing to fully understand what's behind "*argv[]", "static public void" or "IO ()".


> You need to use the IO monad to write "hello world".

This isn't actually true. You need to use a value of the `IO ()` type. Your program would still work if `IO` was not an instance of `Monad`. In a similar way, you also need to use a value of type `String` but you don't care that it implements `Read` or `Ord` or `Semigroup`.

This doesn't entirely invalidate the rest of what you've written - you do need some basic understanding of how to combine IO actions to do any more interesting IO.

But I feel like your presentation is still misleading. "Learn You A Haskell" starts with the REPL, and has you running code in the first tutorial.


Let's be fair to Haskell and LyaH:

I've taught some Java classes. I can get people writing and running trivially useful code before explaining the concepts of "class" and "static". I explain that parts of the code will remain a mystery for a little while until I explain them, I promise to do so, and of course I fulfill that promise as soon as I can.

I feel neither Java nor Haskell are intrinsically bad just because there's no practical way to teach them completely on progressively layered concepts. Even (e.g.) Lisp has a risk of using special forms before understanding them.


Sure, but Learn You a Haskell seem to try to avoid saying "I will explain this mumbo jumbo later" by explaining everything up to type classes before getting to "hello world".

I guess I should write a Haskell tutorial which starts with "hello world" without trying to teach monads beforehand!


Skipping over syntax, I think it's something like:

To write any program in Haskell, you define `main`, the IO action that does the work of your program. `putStrLn` is a function that takes a String and returns an IO action that prints the string.

So we can write "hello world" simply:

    main = putStrLn "Hello, World"
I'm curious whether you actually think that's more useful than building understanding at the REPL.


> I'm curious whether you actually think that's more useful than building understanding at the REPL.

Again, I think this depends on you way of learning. For some people it might be possible to "build understanding" gradually over weeks until you are finally ready to write "hello world" having learnt all the fundamentals of the language. That just doesn't work for me. I need to learn through writing programs which actually does something.


But in the tutorial you are building programs that actually do something - plenty more than simply printing a fixed string. You're just doing it at the REPL instead of in a file.

You keep describing the alternative as if it's a bunch of theory before any practice. It's actually just a slightly different form of practice than maybe you are used to.

I am sympathetic to the notion that it might not work for you, but you haven't spoken at all to the actual distinction. If it really does make a big difference for you, I'm very interested in any unpacking you can do.


To clarify, I am not critical of the language Haskell itself. I think it is great. It is mostly a criticism of the tutorials and general culture around the language.

For example Rust is another language which have a reputation for being hard to learn, due to novel and complex concepts like the borrow checker. But in my experience you see none of this "talking down" to the audience. They just explain how the stuff works with practical examples.


I do understand what a REPL is and have even used one from time to time. But from my perspective, a program which cannot interact with the outside world is literally useless.

It is not an accident that almost any tutorial for any language or framework or platform starts with "hello world". Because you want to start with the minimal but real, working program - and build from there.


I seriously don't see how a stand-alone "hello world" program is meaningfully "interact[ing] with the outside world" in a way that printing a string at the REPL is not. Stop ranting and posturing, and instead please try to unpack that.

In either case you are simply printing a string to the terminal. The standalone program is easier to compose in your shell, which in some contexts matters a lot, but I don't see that it does here. Where is the difference?

Further, if we define "interact with the outside world" in a way that excludes the programmer reading things off the screen, then it's plainly wrong that all such programs are "literally useless". Calculators, for instance, have delivered a tremendous amount of value. I've personally run something at a REPL (in various languages) plenty of times because I had actual use for the value to be printed and didn't need to persist the program.


The point of "Hello world" is that it is the simplest possible real, working program. It can be compiled and executed and you could deploy it to users or to a production environment if you wanted.

"A complex system that works is invariably found to have evolved from a simple system that worked."

I understand that from a certain theoretical perspective it is just the same thing to echo a string literal in a REPL, but from a software development perspective it is completely different.

> The standalone program is easier to compose in your shell, which in some contexts matters a lot, but I don't see that it does here.

I kind of see where you are coming from. You are assuming the program is only ever used by yourself. I understand this is just a different culture and hadn't even thought about that perspective.


> So the reader is expected to read and understand 9 chapters before writing the first program?

Not at all. Haskell has a REPL, so anything involving output is defined as pure functions, then executed at the REPL. For example, here's Quicksort: http://learnyouahaskell.com/recursion#quick-sort That's from Chapter 5.

> I certainly wouldn't be able to learn anything that way.

Certainly not by only reading the table of contents, sure.


Again, this is about different ways of learning which ties into what is even the purpose of programming in the first place.

For academics, the purpose of a program is to exhibit some clever abstraction. So a quicksort which can't take any input to sort and can't produce any output is a perfectly fine program - almost the platonic ideal of a program.

But for developers, the purpose of programs is to do something useful. So learning how to read input and produce output is basically the first thing I want to learn when learning a new language or platform. Because then I can start building small toy programs, gradually doing more and more stuff and learning by tackling the challenges along the way. And implementing quicksort comes way down the line of things I need to learn to write a useful application.


LYAH is full of programs before chapter 9. It does this by living in ghci. Haskell is different - it makes sense for it to start somewhere else (somewhere more useful!) than hello world.


I'm sorry, I don't understand which part of my comment you were replying to.


You are suggesting that newcomers to Haskell should not care about what a monad is. I'm pointing out that tutorials like "Learn you a Haskell" are trying to explain monads before even getting to "Hello World".


> [...] trying to explain monads before even getting to "Hello World".

Chapter 9: Input and Output

Chapter 12: A Fistful of Monads

No, that doesn't seem to be the case to me.


Well then, as you already know I agree with you that this is absurd!

> Yet for some reason newcomers (reputedly) want to know what a monad is before trying to use one! I agree with you: they should go ahead and use one and not worry about what it is!


The one thing that made monads clearer for me was this thing https://youtu.be/b0EF0VTs9Dc Monads and Gonads

It's probably condescending for haskellers because it shows that monads are not some enshrined primary concept but just a kind of dumb wrapper you can write in any language and you do when it's useful for you.


Except that most commonly used languages dont let you have polymorphic typing so the whole point is lost.


>I actually think Haskell is a very enjoyable language, but there is a culture around it which treats the type concepts (arrows, monads etc.) like goals in themselves rather than tools to achieve something useful.

I get it though. The concepts are so advanced that you have to internalize the concept first before it can even be used.


Actually not. It's very hard to internalize the concepts before you've used them!


Yes, I get it, but for Haskell the concepts are so abstract you need to internalize the concept before you start using it.


Those weekly Monad blog tutorials probably annoyed the Haskell community more than anyone. Extremely readable and well written papers had already been published by the Haskell community (e.g. Phil Wadler). Read the papers first.



What confuses me with these tutorials is - who is the intended audience? A person who know what a functor is but doesn't know what a monad is? A person who doesn't know Haskell by do know what >>= means?


Honestly, this blog post is cute but it does not actually give you understanding and insight into these concepts. Imho the only way to internalise these are through practice. Write code, get annoyed by repetition/boilerplate/etc... and discover that abstraction Foo solves that problem.


This is one of two posts that made things click for me. This one clearly distinguishes Functors, Applicatives, and Monads visually so that I don't get hung up on the names every time I encounter them.

The other article that demonstrated the practical purpose or path to constructing Monads showed a number of them using nested procedural syntax formatted to look like do-notation. [I can't remember the title/link, if anyone knows please post.] It went through async/await, maybe or list and showed them rearranged with the 'monad'ic parts off to the right where semi-colons might be.

Do-notation just took that and flattened the nested structures. The appreciation that these different computational contexts could all be structured the same way while focusing on what's happening apart from these contexts really demonstrated why it's useful and the power of being able to encapsulate these seemingly different ideas.

I'm sure I'll need to find a part-3 in my journey (perhaps Monad transformers) and so on, but I've at least got a good footing from those.


The best intro to monad transformers that I've seen so far is https://mmhaskell.com/monads/transformers




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: