11 ms·
Monads are like burritos (2009)
- tengbretson 2y agoAnd we all know that a burrito is just a lasagna in the category of endofunctors.
- koolala 2y agopraise math
- mightybyte 2y agoNot endopasta?
- layer8 2y agoIs that like ravioli code?
- koolala 2y agoHow many bites does a monad burrito take to eat? 90. https://archive.org/details/monadologyotherp00gott/page/217/ https://archive.org/details/monadologyotherp00gott/page/217/ You don't even have to finish eating it to feel full.
- BriggyDwiggs42 2y agoI didn’t know anything about monads before, now I’m curious what the point of one is
- it_citizen 2y agoIt is a widely used analogy generator
- koolala 2y agoF
- MarkMarine 2y agoMaking burritos
- koolala 2y agoBurrito(Veggies)
- momentoftop 2y agoThere's no point as such. They are a natural (non-leaky) generalisation of a recurring pattern in mathematics and software over which you can build some general theory and, in the case of programming languages such as Haskell, a general purpose library. Haskell is one of the few languages that lets you write those general purpose libraries. In other languages, there's really no point talking about monads.
- VirusNewbie 2y agoScala supports it just fine.
- rvense 2y agoA "monad" is a description of something so general it covers lists, things that might not exist, things that might fail, and things that might happen in the future. It is a concept from category theory, which is the branch of mathematics that deals with saying as little as possible about as much as possible. You don't have to worry about any of this unless a teacher tells you to. (And if they do, you can just leave.)
- mmaniac 2y agoHaskell started using them because it allows a pure language to express side effects. Beyond that, they're a pretty general and reusable way of looking at data structures that nest.
- koolala 2y agoBurritos have side effects?
- Y_Y 2y agoMany impure functions take place in Taco Bell bathrooms
- juunpp 2y agoA "side effect" is generally the behaviour that can be modeled by a Monad under chaining (join), and is not necessarily IO (although IO is a Monad). For a burrito, the side effect of join is the union of burrito contents.
- int_19h 2y agoImagine eating a burrito bite by bite as you're performing a pure computation in your head. This would be captured as `Burrito Result` monad, where `Result` is the value that you're computing, and `Burrito` is the partially consumed burrito at the end of the computation. By representing it as a monad, you can pass said partially consumed burrito to someone else for them to compute while continuing to eat it, or you can delegate your computation to other people, passing burrito from one to the other. ~ So, yes, I suppose.
- chuckadams 2y agoA Human Centipede is a Monoid in the category of digestive tracts.
- koolala 2y agoDigital Spreadsheets lets you do this from multiple angles.
- chuckadams 2y agoMonads embody the concept of "chaining" functions. Every monad implements the chaining in a different way, but the user of the monad doesn't have to know how it's done. It's just "call this function on foo, take the result and pass it to the next" and so on. Plain old functions do it with plain old function composition (functions are monads!) but something like Maybe will return None if it gets a None, and only otherwise pass the data on. The Future monad will await completion then pass it on (async/await is a monad!), the List monad will merge together zero or more list results from mapping over each of its items, and so on. Again, the cool thing is that it's the same syntax no matter what kind of Monad you're in, so you can totally change the behavior of a monadic function by just using it with a more specific return type (at least in Haskell, other languages might make you pass around an implementation) Monads are a neat tool of composition, but composing monads themselves is fiddly and cumbersome, involving monad transformer "stacks" of deeply nested generic types. Monad transformers are really just not fun. I'd give specific examples, but I'm kind of lethargic from the burrito I had for lunch. If you're familiar with flatMap(), a Monad is anything that's "flatmappable" (which in JS is just arrays, but languages like Scala take it much further). In C#, it's IQueryable (LINQ is a monad!)
- aodonnell2536 2y agoWould it then follow that commands/builtins like `time` and `sudo` are monads? What about shell commands in general, since you can always chain together stdout to stdin with pipes?
- chuckadams 2y agoStreams are definitely monads, so if you're reading lines from stdin and printing zero or more lines for each to stdout, you basically have a List monad (Haskell's laziness makes every list a poor man's stream, though if you're doing serious streaming work, you'd probably want something more specialized). Mind you, shell pipes aren't actually implemented monadically, but you can certainly visualize it that way when working with functional libraries.
- jerf 2y ago"Monads embody the concept of "chaining" functions." No, it doesn't. Monad implementations may call the provided function zero times, or multiple times. Chaining implies exactly once, one of the common misconceptions about the monad interface. Flatmap is another common attractive nuisance; flatmap is the monad implementation for lists but is not "monad" in general, any more than "an iterator on linked lists" is "iterator" in general.
- kelseyfrog 2y agoIt's an abstraction - a very high level abstraction. Like all abstractions, if you squint hard enough, different things can look the same. Monads can make optionals, lists, error handling, i/o, continuations, state manipulation, reading values, writing values and many other things look the same.
- spion 2y agoThey are interesting in purely functional languages like Haskell because they allow for side effects without sacficicing purity and referential transparency. Rather than allowing side effects, you describe the program as, say, specs for the instruction to run, plus the function that decides what the next instruction is after the first instruction completes and yields a result. Kind of like a linked list of functions that return imperative instructions. I don't think the general concept is that interesting, at least in programming. Monoids, though simpler, are probably way more interesting (mapreduce, caching, etc)
- chuckadams 2y agoMonads are Monoids, so it's a good idea to build up an intuition for Monoids first. Then move up to Applicatives, and then finally Monads if you find you actually need them by then. By the time you get to them, Monads will be boring. Applicatives were dusty theory when I learned Monads, so they never burned themselves into my consciousness. I'm doing good with Monoids tho.
- lkitching 2y agoThe way in which monads are monoids isn't really helpful for understanding them for progamming.
- chuckadams 2y agoI dunno, it helped monads "click" for me at a theoretical level (they're just monoids in the category of endofunctors, what's the problem?) but by then I'd acquired a strong intuition of them already, so maybe it's not helpful for a novice. I'm pretty sure Applicatives help tho, LYAH seems to think so anyway. They sure would have helped me: the "Gentle Introduction to Haskell" was anything but.
- spion 2y agoMonads being monoids isn't very interesting in a practical sense - e.g. just because you can associatively combine steps in a program isn't very interesting. (We do it all the time when we extract a subset of instructions as a procedure) I'd say monoids are more interesting, mainly due to implications for massively parallel algorithms and caching and how finding operations that fit the laws let you reap massive benefits in both aspects. I've yet to see something as practically interesting for monads. Perhaps monadic parsers or STM qualify. What would you say makes monads just as interesting in a practical sense?
- program_whiz 2y agoThe easiest examples from mainstream languages are things like Result<T>, Future<T>, or Option<T>. Its honestly a very broad and vague way to say "some data with context". The advantage is that instead of using things like exceptions or panic/crash, your code must handle every case in order to get at the value unlike the normal case. For example, an Option<T> could force you to unwrap the value and deal with errors. In true functional languages and/or where pattern matching is used, you must handle both cases, presumably creating a chain of "monads" all the way down (as most of your functions will return Option<T> or Result<T, Err> type patterns, since you can't throw an exception, and any value might be empty/error, so you have to propagate it upwards). Honestly its a fancy term that functional programmers use to cow the laity. Its a bit like calling an if statement "probative procedural data query with indeterminate flow control."
- chuckadams 2y ago> Its a bit like calling an if statement "probative procedural data query with indeterminate flow control." Yeah, but "Monad" goes in the opposite direction, two syllables to sum up the whole deal. Also pretty typical for functional programmers :)
- lr4444lr 2y agoAssuming you're familiar with basic programming concepts, it is practically speaking just the abstract definition of a way to ingest and pass around data in an unfamiliar context. Promises are a great example (packaging data for async processing), or the "Optional" wrapper on JVM return signatures (Passing around an object for possible-null handlers). Both those implementations fail on some purity grounds, but they're good for understanding the gist of your question, i.e. "the point" of one. (Even though I'm 73% sure some Haskell-ite is going to respond to me with an _ACTUALLY..._)
- Tarean 2y agoLambdas have two hidden features: Variable capture lets you access variables/values from outer scopes, and statements/calling other functions lets you do control flow. Monads are types that let you build chains of lambdas, so you can mix control flow and variable scoping with the some type-specific logic. Async IO/streams/optionals are monads. It's no accident that these could be programmed as nested callbacks/nested loops/nested if statements. That's the nested chain of Monad->lambda->Monad->... Monads work well with syntax sugar (think async/await), and some languages like Haskell can abstract over them in neat ways.
- ww520 2y agoMonad provides a way to wrap types of data to process and chain them uniformly.
- bbminner 2y agoFor me, everything made sense when I read that generator functions in python can be used to implement algebraic effects, and algebraic effects and monads express the same ideas/logic using somewhat different language (and for some, including me, the algebraic effect lagngauge is easier). So I like an explanation that goes like "langaues without either but with exceptions and async io > generators/coroutines > algebraic effects > monads". On a fundamental level, all these describe abstraction over what happens "between functions calls" and how values are passed around. 1. Some languages provide special syntax for exceptions and async io - in both cases "something" might happen between function calls - either an exception handler is called under certain constitutions (eg prints logs) or a kernel level callback is created and the program is suspended. 2. One generalization of this can be implemented using python generator functions / coroutines - you can build a call graph by invoking all functions in you callstack as "yield from func()", and use "yield Exception" to propagate errors and "yield Timer(1)" to ask an outer caller (event loop) to wait, or "yield Print(mag)" if we want to keep our functions pure and make the C event loop handle all the IO. You can also pass values down the stack via corp.send(x). 3. But it is a little clunky. Some langaues like Koka give you an ability to define arbitrary "effects and effect handlers" which is essential special syntax for how we were abusing coroutines in the previous step that makes differentiating and handling different "kinds things that we pass up and down the callstack" (exceptions vs timers vs prints) easier. 4. But some langaues do not have effect handlers but still want to do "custom arbitary custom things between function calls". That's where monads come in - they define a type for defining chains/trees of function calls and rules for how these threes must be iterativley unwrapped and wrapped back depending on how the wrap looks like. Eg instead of doing a(b(c)) you say unit(c) | b | a and describe how piping must be done it terms of types of values that these steps process. I hope it makes it clear how one could implement side effect IO, or exceptions, or async io that pauses by defining how to "unwap such piping". In principle, you abstract away control flow by introducing your own syntax for building function call trees and then rules for writing piping that works with such trees. Monad guru please correct me if I am wrong.
- trealira 2y agoI think a good write-up that shows some practical use cases of monads is a paper called "Monads for functional programming" by Philip Wadler. It assumes you're familiar with the basic syntax of Haskell or its predecessors, though. https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/b...
- lkuty 2y agoGood tutorial I think and I also appreciated reading the beginning of https://wiki.haskell.org/All_About_Monads https://wiki.haskell.org/All_About_Monads and watching "Don't fear the Monad" https://www.youtube.com/watch?v=ZhuHCtR3xq8 https://www.youtube.com/watch?v=ZhuHCtR3xq8
- draw_down 2y agoI don’t know how many times I’ve read things like this but it doesn’t seem to click. It’s like a burrito with map and bind functions? Well, alrighty!
- vendiddy 2y agoYeah seriously. I feel like these kinds of concepts I to hear a few concrete examples, then generalize. These analogies usually don't click with me.
- chuckadams 2y agoThat's actually the point of the article. There used to be a cottage industry in using real-world analogies to explain Monads. I'm not sure whether it started as an in-joke or not, but the most outlandish metaphor among others involved burritos (other metaphors out there that really did exist: assembly lines, toxic waste handling, and space suits). So now burritos are an in-joke among Haskell programmers, sort of a whimsical shibboleth. Check my other post in this thread for what I hope is a more accessible explanation of Monads. They're a very abstract thing, so there's no concrete metaphors to be had, just a common thread of piping values through "contextful" functions.
- throwaway689236 2y agoYeah, seems like a lot of articles are written just to have a catchy title.
- tiagod 2y agoThis was actually a great explanation. Still delivering 15 years later. I wonder what other mathematical constructions are abstractions of burritos.
- Waterluvian 2y agoThe application of the red sauce to the tortilla when the burrito is resting on the plate describes a transverse Mercator projection.
- passion__desire 2y agoI have a general rule about abstraction. If the abstraction is so general (e.g. a root node of a tree of abstractions), then it's qualities will be reflected in every leaf node. Leaf nodes such as snow, rock, water, trees or burrito.
- ldjkfkdsjnv 2y agoFunctional programming is dead. It never really caught on. For all the articles I saw from 2010 - 2020, functional languages are still as niche as ever. Influential languages like scala have their best functional features pulled into java. LLMs will further accelerate the decline. All the highest quality, most crucial software I have seen is written in something like Java, using classical OOP design patterns.
- TwentyPosts 2y agoCounterpoint: Rust. Seems to be taking off (difficult to predict the long-term, of course), but Rust is excellent at functional paradigms and Brings many advancements of functional languages to the people.
- ldjkfkdsjnv 2y agoRust is still extremely niche, large scale mission critical software that runs big tech is not written in Rust
- rcxdude 2y agoit's getting built into some pretty widepread applications: firefox is a big one, it also runs a lot of the super-low-level parts of dropbox. I'd say it's overtaken haskell for adoption at least.
- SoftTalker 2y agoBecause it's really better, or because it's trendy?
- chuckadams 2y agoIt's more practical. I love me some Haskell, but you're never going to write Servo in it.
- TwentyPosts 2y ago
- 12_throw_away 2y agoI often forget what a monad is, and need to keep reminding myself "remember list.map and Option.and_then? if so, then you don't need to know what a monad is". But will try thinking about burritos next time to see if it helps. I still don't get what they have to do with i/o in Haskell, but am ok with i/o in Haskell being one of my life's forever unknowable mysteries.
- sunshowers 2y agoThe way I think about it is that the general monadic structure is that the results of an operation can cause new operations to happen with equivalent complexity. This is exactly what "flat map" is. So what the "IO monad" in Haskell represents is the general principle across programming languages where you can, say, read a file, then for each line in the file read another file or otherwise do additional I/O -- and this can spiral out in an unbounded fashion. As developers we can observe the monadic structure of operations everywhere (and generally seek to avoid it! Monads are fundamentally too powerful!) But whether it is worth encoding the general idea of monadic structures into the type system is a separate question. Haskell says yes, most others say no. There are good reasons both ways. (One underappreciated reason is that exposing a hierarchy of typeclasses/traits introduces API stability considerations. When Applicative was inserted in between Functor and Monad in Haskell, the whole ecosystem had to be updated.)
- roflc0ptic 2y ago(Tries to fight the urge to explain, fails) it’s a construct to sequence async interactions, one after the other, without blocking. It’s very similar to c# or python’s await
- minitech 2y agoI/O is just one thing that can be described with a monad. `Option` with `and_then` as the parent suggested was another example.
- roflc0ptic 2y agoYeah the subject of my sentence was unclear. I was responding to the comment about IO in particular.
- gabesullice 2y agoI've referred to this blog post at least twice a year since I read it 6 or 7 years ago. Not because I need to explain monads, but because the "monad tutorial fallacy" [1] is an incredibly useful concept to be aware of when trying to convey knowledge. I encourage you to read about it :) [1] https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/ https://byorgey.wordpress.com/2009/01/12/abstraction-intuiti...
- Symmetry 2y agoThat reminds me of giving the advice, "Just do what comes naturally," to beginners. That's the last advice someone who has spent years building up an intuitive model needs, but it's terrible for beginners. https://putanumonit.com/2021/09/10/rules-for-noobs/ https://putanumonit.com/2021/09/10/rules-for-noobs/
- Swizec 2y agoJust do what comes naturally is great advice for beginners. See the pottery class parable: https://www.industryweek.com/leadership/companies-executives/article/21961057/pottery-class-a-parable-for-idea-generation https://www.industryweek.com/leadership/companies-executives... tldr: Pottery class, 2 groups. 1 group instructed to make the perfect pot (graded by quality of 1 best pot). 1 group instructed to make a bunch of pots (graded by pounds of clay used). At the end of semester, the group who was trying to make as many pots as possible also produced the single best pot of the class. Lesson: You need reps. Lots of reps. You really do just gotta do what comes naturally, get feedback, then do more. Doing is the only way to learn tacit skills. You can read about the best way to ride a bike for 10 years and achieve nothing. Or you can spend an afternoon failing a lot until you can ride a bike. Software architecture and code structure are similar. You just gotta produce piles upon piles of code and see what works.
- deleted 2y ago[deleted]
- int_19h 2y ago
- behnamoh 2y agoMonads are so easy. That's why there are 2,000 articles online explaining how easy they are. :) Okay hear me out: I don't like exception handling, because it doesn't feel "pure" and consistent with the rest of my program flow. If any errors happen, I want to know what they are so I can plan ahead. You might say "well, just catch your exceptions dammit". But see, what if I forget to catch an exception right away and it propagates? Also, other than Swift, I don't know of any programming language that let's me explicitly mention if a function could throw an exception. In Python, for example, you can't just do Optional[str], because returning None is different from raising an exception. So by just looking at a function type signature, one can't know if it throws, which means you never know if you should use try/catch or not. But let's say you take care of all edge cases and return None in those bad paths instead of raising exceptions. Let's also assume that Python does't suck and it never raises exceptions by its own standard libraries (e.g., json throws). The problem is: How do we know if the function returned None because the evaluation was None, or because it failed at some point? So a better approach is to explicitly say the function returns "something" which may or may not be there. If it's there, then the function worked correctly, even if the value is None. If it's not there, then the function failed. Go does this. Rust does this better. Haskell has had this since ages thanks to Monads. I like to think of monads as wrappers around data. In Python, I simply write a Result monad (similar to Rust). In Haskell, this is called a Maybe monad.
- chuckadams 2y ago> I like to think of monads as wrappers around data Technically they're a wrapper around a data type. Maybe Foo is a Foo that might not be there, [Foo] is zero or more Foos, etc. Which is actually describing a Functor, but Monads are also Functors, the "monadness" comes from the particular functions like `bind` (or `flatMap`) that work on them.
- airstrike 2y agoYou might enjoy Hurl, the exceptional language: https://news.ycombinator.com/item?id=40480056 https://news.ycombinator.com/item?id=40480056
- 2y ago
- justinpombrio 2y agoJerf wrote a great monad tutorial for people who have read too many monad tutorials (like this one): https://www.jerf.org/iri/post/2958/ https://www.jerf.org/iri/post/2958/
- scythmic_waves 2y agoThank you! I was trying to find this the other day but couldn't.
- SatvikBeri 2y agoMy favorite approach is from Functional Programming in Scala, which doesn't mention monads until chapter 11. But it has you implement a bunch of collections with `map`, `map2`, `unit`, and `flatMap`, and exercises that repeatedly show how useful this interface is. So by the time you get to it, the definition of Monad feels obvious, as well as Functors & Applicatives.
- jimbokun 2y agoI like that, because I feel like every time I read about Monads, the question “why is this a useful abstraction?” is rarely addressed.
- brudgers 2y agoNot really related, https://the21stcenturymonads.net/ https://the21stcenturymonads.net/
- Mathnerd314 2y ago> But he said no, I was the lone genius. I think that's the issue? Haskell was designed by and for geniuses (Larry Wall). But Python... certainly Guido likes compliments but for the most part he was an average programmer, designing for other average programmers. And now Python is #1 while Haskell is only #28. Like if you just skipped the "monad" terminology and called them "promises" or "futures" everybody would be less confused.
- int_19h 2y agoI don't think Guido is "an average programmer". But Python is a distant descendant of the ABC programming language (https://homepages.cwi.nl/~steven/abc/programmers/handbook.html https://homepages.cwi.nl/~steven/abc/programmers/handbook.ht...), which, as the name implies, was meant as a better alternative to BASIC and Pascal for teaching.
- avodonosov 2y agoExplanations with bad analogies are really a very often problem. Although this author matched monads with burritos relatively well. Except for the purpose - we know the purpose of burritos, but this does not help to understand the purpose of monads (for programming, in particular). But sometimes a concept is named after a bad analogy by the concept authors (and probably even invented after that bad analogy, although maybe the authors just use poor name because they fail to clearly recognise the essence of their solution). Like mixins. I satirise that in my Mixin FAQ Q: What is a mixin? A: Mixin allows to inject functionality into classes. Mixins first appeared in the Flavors system and were inspired by an ice cream shop offering a basic flavor of ice cream (vanilla, chocolate, etc.) with a choice of optional "mix-in" ingredients like nuts, cookies, candies, etc. Q: Can I mix-in a ServerSocket into a ColorPicker? A: Yes, why not. Q: How will it work? A: Like ice cream with cookies.
- frabjoused 2y agoIs something that is so inherently hard to explain while giving it justice truly practical or even worth it? If you are in a room with 10 devs, how many will have a deep understanding of monads? And if it is expected to be only a few, is it really constructive to have it in the codebase? Or is it just going to trip people up and be misapplied.
- williamcotton 2y agoIf your codebase is written in F#, OCaml or Haskell then it would be surprising if there were no use of monads as it is a pretty common design pattern in a functional language.
- bawolff 2y agoI think the real question is more - is the language of category theory really worth it here. Monads as a concept is basically just a fancy version of a wrapper class (if you in OOP land). Do we really need the cognitive overhead of advanced mathematics to explain that?
- agentultra 2y agoYou can get by on intuition but you won’t get far. If you want to limit yourself and make sure people keep reinventing the same concepts over and over, sure, avoid maths.
- acdha 2y agoThis comment would be stronger with some kind of examples or other reasoning about the kind of problems this avoids. In particular, the dichotomy you created which paints the two options as “advanced mathematics” and “intuition” seems to need some proof that there is no third option. Since the original poster mentioned OOP, that would be a good place to start with some example of a problem which is hard to avoid following good OOP practice.
- agentultra 2y ago
- massysett 2y agoMonads are easy. What’s hard is higher-order functions, parametric polymorphism, and ad-hoc polymorphism via typeclasses. Understanding any one of these is hard. Understanding all three is harder. Understanding all three applied simultaneously is harder still. That’s what monads are. On top of all that, understanding “monads” doesn’t mean too much. IO does something, Maybe does something else, StateT something else. But once you understand all that, monads are easy. Maybe monad analogies helped somebody understand all that, but they didn’t help me.
- MarkMarine 2y agoThis should be a blog post :) Tongue in cheek but seriously, I was pretty happy with my working understanding of monads and now I’m questioning it. Would love to hear you elaborate or link references so I can learn more
- williamcotton 2y agoA Burrito Is a Monad (2024): https://www.williamcotton.com/articles/a-burrito-is-a-monad https://www.williamcotton.com/articles/a-burrito-is-a-monad let burrito = tortilla >>= addMeat Chicken >>= addMissionBurritoIngredients >>= holdThe Cheese >>= addIngredient PicoDeGallo >>= addIngredient Salsa >>= addIngredient Guacamole >>= addIngredient SourCream
- davesque 2y agoI always felt like the one thing I wanted in a monad tutorial was a list of things that aren't monads because they follow all the monad rules except for one, for each rule.
- bedobi 2y agoHere’s my monad tutorial for programmers A monad is anything you can flatmap with The monad of list is you flatmap a list on a list and instead of getting a list of lists, as you would if you just mapped, you get a single flattened list Thanks for attending my ted talk
- binary132 2y agoOk, so everyone confusing me with bad explanations of monads was just confused all along and they are simple. Is that all this was ever all about then?
- MarkMarine 2y agoIt’s pretty perfect this comment stream has gone from a couple jokes to people (poorly) explaining monads. Basically we’ve gone from the Monads are like burritos joke to the examples of the monad tutorial fallacy blog post in 91 comments. chefs kiss perfect.
- gaganyaan 2y agoThis is still the best, simplest explanation of monads I've ever seen, no burritos required: https://www.adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html https://www.adit.io/posts/2013-04-17-functors,_applicatives,...
- penguin_booze 2y agoKnock yourselves out: https://wiki.haskell.org/Monad_tutorials_timeline https://wiki.haskell.org/Monad_tutorials_timeline. Obligatory condescending "explanation": Monads are just Monoids in the category of endofunctors. What's your problem?
- randomtoast 2y agoI think it is best just to provide the mathematical definition, provide the commutative diagrams that explains the concept graphically and then provide an example for computer scientists in Haskell: https://beuke.org/monad/ https://beuke.org/monad/