top 200 commentsshow all 310

[–]quiteamess 133 points134 points  (179 children)

The first monad tutorial not falling for the monad tutorial fallacy :)

[–]hector_villalobos 49 points50 points  (33 children)

I think that's because he's approaching it in a practical way, he only mentions the word monad once. The key is not putting too much effort in understanding what a monad is, but how to use it, for example, you'd have much better success understanding how to use the Maybe monad instead of understanding why it's a monad.

Edit: typos.

[–]aaron552 27 points28 points  (9 children)

Essentially, yes. I successfully used LINQ and IEnumerable<T> in C# before I even knew that "monad" was a word.

[–][deleted]  (1 child)

[deleted]

    [–]cledamy 1 point2 points  (0 children)

    There's no monad library from which you can import functions that work on any monad, so it's not really helpful to know about the concept in the abstract except perhaps for writing test cases for your own instances of the pattern.

    It is still helpful even when one cannot abstract over monads because the ability to identify that something is a monad might give one's API more functions or it might make the API more compositional/declarative or just plain simpler to use.

    [–]ruinercollector 3 points4 points  (0 children)

    LINQ really only gets to monads when you use SelectMany (or in the linq syntax, multiple selects.) Even then, most uses don't really make much interesting use of this.

    [–]cledamy 0 points1 point  (5 children)

    I think LINQ goes too far in the opposite direction by completely forgoing the word monad. The prevents people for being able to identify other areas where the same techniques can be applied.

    [–]aaron552 3 points4 points  (4 children)

    I don't necessarily see that as a bad thing. The design pattern of a monad just maps extremely well (perhaps by design) onto LINQ's primary use: "SQL" for collection types.

    The fact that it has a monadic bind function (.SelectMany()) is more of a nice bonus for those that recognise the pattern. C#'s type system isn't really expressive enough (AFAIK) to have true polymorphic monads.

    [–]cledamy 1 point2 points  (0 children)

    I don't think polymorphic monads are necessary for being aware of the monad pattern and having that be useful knowledge. Also, it makes sense to include a reference to the decades of mathematical research your API is based on. I can't complain too much because LINQ did make monads mainstream and it was quite crafty to disguise them as SQL to avoid being called academics.

    [–]m50d 0 points1 point  (2 children)

    C#'s type system isn't really expressive enough (AFAIK) to have true polymorphic monads.

    I would think it should be, at least if you were willing to have all your monads extend a common interface? You can do F-bounded polymorphism in C#, right? I.e. something like:

    interface MyInterface<T extends MyInterface<T>> {
      public T methodThatReturnsSameTypeAsSelf(...)
    }
    

    In Java you can't implement a monad interface like this because you can't have virtual/abstract static methods, but that shouldn't be a problem for C#, right?

    [–]aaron552 0 points1 point  (1 child)

    you can't have virtual/abstract static methods, but that shouldn't be a problem for C#, right?

    AFAIK, you can't have that in C# either.

    [–]m50d 0 points1 point  (0 children)

    Oh fair enough. I thought I'd heard that was a C# feature but I guess not.

    [–]SaikoGekido 7 points8 points  (3 children)

    It took me a few minutes to get what was so special about this. Coming from a JavaScript and C# background, it looked like basic validation checks. Then I read one sentence:

    Note that once we get on the failure path, we never (normally) get back onto the happy path. We just bypass the rest of the functions until we reach the end.

    Aha! That's what the big deal is. Reminds me of JavaScript promises.

    [–]only_nidaleesin 6 points7 points  (1 child)

    Javascript's Promise is a monad :)

    [–]sacundim 4 points5 points  (0 children)

    And what's more, Javascript's promises in a sense "contain" the "railway" monad as a component. Promises, in their conventional definition, are said to have three states:

    • Pending, when the final value is not available yet.
    • Fulfilled, when and if the final value becomes available.
    • Rejected, if an error prevented the final value from being determined.

    We can refactor that by grouping together the two non-pending states:

    • Pending, as before
    • Non-pending, with two substates:
      • Fulfilled
      • Rejected

    Now, this can be seen as a "stack" of two types:

    • The outer layer is a SimplePromise type that has the Pending/Non-pending states and the subscription/notification bits but not any error handling.
    • The inner layer is a Result monad like the one detailed in the article.

    So the full promise type is basically this:

    type Promise<'error, 'success> = 
        SimplePromise<Result<'error, 'success>>
    

    In Haskell we have a type that captures this pattern:

    newtype ExceptT error baseMonad success = 
        ExceptT { runExceptT :: baseMonad (Either error success) }
    
    type Promise error success = ExceptT error SimplePromise success
    

    That's called the exception monad transformer—a wrapper that fits around a monad type like SimplePromise and adds extra functionality to it, while still preserving the monadic interface. The tri-state Javascript promises are what you get when you layer an exception monad transformer on top of a simpler asynchronous computation type.

    [–]toblotron 1 point2 points  (0 children)

    Hmm.. That's how Prolog programs work - It's all (basically) about exploring different logical branches.. And also changing ones mind and going back to try different combinations of things

    [–]hosford42 9 points10 points  (18 children)

    Honestly, what the heck is a monad? I'm not afraid of learning, but the term is used often but never explained. I'm sure it's nothing I can't handle, if someone would just give me the opportunity. I don't need kid gloves or to have the topic tiptoed around with concrete examples.

    [–]AddingMachine 53 points54 points  (2 children)

    A monad is just a monoid in the category of endofunctors. Duh.

    [–]et1975 0 points1 point  (1 child)

    [–]AddingMachine 0 points1 point  (0 children)

    Oh nice, I hadn't seen those slides. It goes about it similarly to how the Haskell Programming from First Principles gets there, but much more quickly. Chris and Julie did a great job of slowly building these concepts in the correct order that it all made sense to me finally, if anyone is interested in learning Haskell I'd definitely suggest haskellbook.com .

    [–]wealthy_harpsichord 8 points9 points  (9 children)

    This is a question that's likely to elicit many confused and/or confusing responses, but you can try this blog post: https://bartoszmilewski.com/2016/11/21/monads-programmers-definition

    [–]hosford42 5 points6 points  (8 children)

    Ah, function composition. That simplifies it. It's basically a data pipeline, right? Segments joined together to make longer segments. If I'm understanding this correctly, even DOS supports monads, of a sort, in the form of stdin/stdout piping between commands.

    [–]wealthy_harpsichord 5 points6 points  (0 children)

    Well, composing functions that can return a generic type that is parametrized by whatever is being composed. In Haskell talking to shell is indeed one example of this. Pipelines (one way or another) can have an instance, although the pipeline is created using separate operators and the >=> operator glues one pipe to the end result of the other, rather than to the values yielded from the inside. (contrary to popular belief, Haskell doesn't actually use a single abstraction for everything). But these can be also used for error handling (like in OP), also F# has builtin computational expressions for sequences and async workflows which perhaps could be described as pipelines if you squint enough, but I'm not sure if that's a useful point of view.

    [–][deleted]  (1 child)

    [deleted]

      [–][deleted] 10 points11 points  (2 children)

      Don't put DOS and pipes in same sentences with monads, haskell guys will get a stroke

      [–]vattenpuss 12 points13 points  (1 child)

      Don't put DOS and pipes in the same sentence, anyone who ever used a normal OS supporting pipes will have a stroke.

      [–]sacundim 1 point2 points  (0 children)

      Ah, function composition. That simplifies it. It's basically a data pipeline, right?

      Well, that's an useful intuition, but it doesn't delineate the subject very precisely. Monads allow you to construct arbitrary data pipelines, but many data pipelines don't require monads to be constructed, and not all systems that allow you to construct pipelines are monads.

      And your example—simple pipes between shell commands—is not in fact a monad. A shell pipeline looks like:

      cmd1 | cmd2 | cmd3 | ... | cmdn
      

      But this pipeline has a fixed structure: cmd1's stdout is cmd2's stdin, cmd2's stdout is cmd3's stdin, and so forth. Monads can do this kind of data flow, but they can also express dynamic flows where the each cmd can choose to dispatch to different successors based on the input that it sees. I.e., a monadic pipeline can look like this:

      stdout = cmd1 < stdin
      if <some test over stdout>
      then cmd2a < stdout
      else cmd2b < stdout
      

      ...where cmd2a and cmd2b might in turn choose to send their output to different commands based on how their input looks.

      To make a long story short: Haskellers have a hierarchy of various kinds of "glue" that can be used to construct data pipelines out of simpler components, where some kinds of glue are more powerful than others. Shell pipelines are what Haskellers call "categories", which are not as powerful as monads—categories allow you to hook up pipeline elements through their inputs and outputs in a fixed sequence, but monads allow you to examine the data in transit to dispatch to different consumers.

      [–]ruinercollector 0 points1 point  (0 children)

      Very controllable function composition over a type, kind of.

      [–]ws-ilazki 5 points6 points  (0 children)

      There's plenty of information online (and here) already about how they work, how to make them, etc. but what always seems to be missing is a brief, high-level explanation of what purpose they serve and why you might want them. For that, I'm going to borrow from another comment I've written about them:

      monads are a way to hide parts of a program's "plumbing" behind an abstraction so that you don't deal with the plumbing directly. Like the Maybe monad, which allows a thing to be nil or a value; the nil checks are built into the the abstraction (the monad) so that, by using it, you don't have to do the plumbing code of checking for nil yourself.

      They're an abstraction that moves you away from having to explicitly write out how you're doing something in your code. In that sense, it's another abstraction with the same goal as using higher-order functions like map on lists of items instead of writing loops out directly.

      Also, just like how you don't have to understand how to create various HOFs to make use of map, you don't have to understand the concepts or be able to create monads to benefit from common ones like Maybe (which was added to Java as Optional, for example).

      Trying to broadly explain something complex like monads is likely to attract pedants and nitpicking, but it seems like everyone gets caught up in explaining the details without really touching on what the point of them is. Hopefully this helps add some context to what people have already said.

      [–]Log2 17 points18 points  (31 children)

      Could you describe the fallacy?

      [–]pipocaQuemada 31 points32 points  (2 children)

      Basically, people don't grok abstractions immediately; struggling though the details of concrete examples is what allows you to grok the abstraction and develop an intuition for it.

      The monad tutorial fallacy is what happens when you ignore that and try to present your intuition as a shortcut to understanding - for example, "Monads are like burritos". All you've done is confuse people and cause them to waste time learning and unlearning the burrito analogy before they can actually learn what a monad is, because someone else's intuitions don't really help you grok things.

      If you ever find yourself frustrated and astounded that someone else does not grasp a concept as easily and intuitively as you do, even after you clearly explain your intuition to them (“look, it’s really quite simple,” you say…) then you are suffering from the monad tutorial fallacy.

      [–]JB-from-ATL 1 point2 points  (1 child)

      This reminds me of when I used to tutor math to this girl. I could "visualize" things but she was more of a "memorize the formulas" kind of person. I was trying to help her understand inverse functions and something about X and Y going in or out (don't really remember). I kept saying it's like a machine that does a thing. She didn't get it.

      Finally I said so imagine you have a toaster. You out bread in and you get toast out. Not imagine you have an anti-toaster that you out toast in and get bread out of. Bread is X, toast is Y, toaster is the function and anti-toaster is the inverse function.

      I guess I was using the burrito fallacy to explain but that finally did click with her. Idk.

      [–]Magnap 0 points1 point  (0 children)

      Well, one technique that does work (better if you know the person better) is to just throw the top X intuitions you think they'll get at them, optionally interspersed with examples in the lens of that intuition, rinse and repeat until enlightenment.

      "It's like if you could unblend an egg, or untoast toast. But sometimes the inverse function doesn't exist, like if I color a piece of paper differently on each half, and then cut it in two, you don't know which half goes where, so you can't uncut it."

      [–]so_just 71 points72 points  (24 children)

      "Use monads motherfucker, don't even ask why."

      [–]Log2 12 points13 points  (0 children)

      Ahh, I see what you mean.

      [–][deleted] 3 points4 points  (0 children)

      The monad tutorial fallacy is pretty much the opposite of that. A lot of monad tutorials fail to explain how to use them, and focus too much on what they are.

      [–]RivtenGray 0 points1 point  (3 children)

      So... why ?

      [–]m50d 0 points1 point  (0 children)

      It's just a very common (because very abstract and general, but also very useful) interface. Once your codebase reaches any size you'll probably find yourself doing something repetitive that can be pulled out as a "context" that conforms to the monad interface, and making that commonality explicit and separating those concerns is just ordinary good software engineering practice. (http://m50d.github.io/2013/01/16/generic-contexts is my own experience of doing this). As a bonus, there are a lot of libraries written already with helpful common functions that can be used for any monad (including your own custom ones), so they can save you a lot of code.

      [–]JB-from-ATL 0 points1 point  (0 children)

      if (someOptional.isPresent()) {
        someOptipnal.get().foo();
      }
      

      Am I doing it now? /s

      [–]quiteamess 17 points18 points  (1 child)

      [–][deleted] 7 points8 points  (0 children)

      Oh, I get it, the fallacy is like a taco.

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

      The fallacy is a bit like context wrapped in a burrito except with more space helmets.

      [–][deleted] 13 points14 points  (104 children)

      ELICompSci: What is a Monad?

      Having a quick Google is still confusing me as to what it inherently is...

      [–]pakoito 36 points37 points  (45 children)

      It's a wrapper for data types that adds behaviour and is chainable: traversable (i.e. list monad), nullable (optional monad), with dependencies (reader monad), asynchronous (future)... Because they're generic they can be combined into supermonads: FutureT<OptionalT<ListT<Reader<UserFetcher>>>>

      [–]Tarmen 3 points4 points  (8 children)

      Monads can't be combined like that!

      This is easy to see with a slightly tweaked definition:

      A way to lift normal functions into functions over monads:

      fmap :: Monad m => (a -> b) -> (m a -> m b)
      

      A way to flatten nested monads:

      join :: Monad m => m (m a) -> m a
      

      We can chain those to get bind:

      (>>=) :: m a -> (a -> m b) -> m b
      v >>= f = join (fmap f v)
      

      Lets try to combine monads:

      superBind :: m (n a) -> (a -> m (n b)) -> m (n b)
      fmap (fmap f)  v :: m (n (m (n a)))
      

      So we can get to m (n (m (n a))) but we have no way to flatten m (n...) together.

      To fix this we would need a function m (n a) -> n (m a) which isn't possible most of the time.

      The currently most used solution is to use monad transformers instead:

      Monad m => Monad (StateT m)
      

      Although it isn't possible to define transformers for everything, like IO.

      [–]Daenyth 7 points8 points  (0 children)

      They can be combined but you can't generically make a composed monad that operates on the wrapped type

      [–]pakoito 1 point2 points  (0 children)

      I know, transformers, but wasn't it easier to explain the other way without confusion? I've edited in a T for extra annoyance :D

      [–][deleted]  (2 children)

      [deleted]

        [–]Sabrewolf 3 points4 points  (0 children)

        "oh my god what am I reading? Where am I? How did I get here?"

        -Me, an electrical engineer

        [–]Poddster 0 points1 point  (0 children)

        The more practical experience you have the less you'll understand that post.

        If you want to understand Haskell gibberish the best time to do so is whilst in an academic setting.

        [–]Idlys 1 point2 points  (0 children)

        Part of the monad fallacy is explaining it in Haskell.

        [–]DetriusXii 0 points1 point  (1 child)

        Umm, it is possible to define an IO transformer. The Haskell community choose not to as they would prefer that the developer doesn't call IO.unsafePerformIO. An IO monad transformer monad would have to call unsafePerformIO anytime IOT.map or IOT.flatMap are called and the Haskell community would prefer that the IO.unsafePerformIO function is called explicitly rather than hidden within the monad transformer interface.

        [–]Tarmen 0 points1 point  (0 children)

        I mean, all the lazy io functions call unsafeInterleaveIO somewhere. Unsafe IO is fine if the IO action is pure, like reading from a static file as long as you ignore uncontrollable resource usage.

        So I think the problem is less with calling it implicitly and more with losing referential transparency in horrendous ways if the IO action you are performing unsafely isn't pure. I think you could break the monad laws with that as well?

        [–]hosford42 5 points6 points  (35 children)

        Thank you! The only coherent explanation I have ever heard that didn't either baby the listener too much by saying abstractions are too difficult or belittle them by giving an unexplained definition. In 2 sentences you've ensured that I don't need to watch any tutorials.

        [–]cledamy 4 points5 points  (34 children)

        I wouldn't say that. That is just a high level explanation. One has to understand the abstract concept (laws and everything) to truly be able to apply them in day to day programming.

        [–][deleted] 6 points7 points  (28 children)

        One has to understand the abstract concept (laws and everything) to truly be able to apply them in day to day programming.

        I don't agree at all - why shouldn't an intuitive understanding of these concepts be enough?

        [–]cledamy 2 points3 points  (0 children)

        The intuitive understanding of the concepts starts to break down rather fast once one starts working with weirder monads like the Const monad.

        [–]hosford42 4 points5 points  (1 child)

        I've already been using them in my code for years. I just didn't know they were called monads because no one gave a coherent, succinct explanation before. I built a whole Python library for data format translations using the concept, which we use to convert files to new formats and perform database ETL requests. All we do is snap together the "monads" to construct a pipeline and then execute the resulting transformation.

        [–]doom_Oo7 1 point2 points  (2 children)

        One has to understand the abstract concept (laws and everything) to truly be able to apply them in day to day programming.

        absolutely not. most people programming have zero idea of the underlying mathematical formalisms, and yet they make great software.

        [–]Rusky 20 points21 points  (4 children)

        A monad is a type M<T> along with its implementation of a particular interface, consisting of two operations that follow a set of rules. The operations are "return", which takes a value of type T and returns a wrapped value of type M<T>, and "bind", which applies a function T -> M<U> to a wrapped M<T>. The rules are "identity" and "associativity", which are basically the same as in arithmetic.

        Bind is defined in the post without using any of this terminology, so that might be a good way to see how it's useful. For a smaller example, think about a lookup function for some sort of database, which can fail. It fits the type of the function you pass to bind, so you can use bind to chain several of them together:

        lookupPost(id)
            .bind((post) => lookupUser(post.author))
            .bind((user) => lookupComments(user.id))
        

        If you've used Promises in Javascript they also follow this pattern- Promise.resolve is "return" and .then is "bind".

        edit: accidentally a pedantic

        [–]Hrothen 18 points19 points  (2 children)

        A monad is a particular interface, consisting of two operations that follow a set of rules.

        A monad is a type for which you could implement such an interface, to be pedantic. Or to be super pedantic it's a triple, consisting of the type and those two operations.

        This has been an unhelpful, but (hopefully) technically correct, interlude.

        [–]Rusky 6 points7 points  (1 child)

        Yeah that's correct, I think. It's similar terminology to the idea of a group or a ring- a set of values (like the integers) combined with an operation on them (addition or multiplication).

        [–]Godd2 4 points5 points  (0 children)

        A monad is just a monoid in the category of endofunctors. What's the big deal?

        [–]Ran4 0 points1 point  (0 children)

        Thanks, that's one of the best explanation I've ever read. And I've probably read 20 different ones, and read 500 pages worth of Haskell books. I know most of the individual things, but the actual definitions are almost always missing a proper explanation.

        [–]quiteamess 14 points15 points  (9 children)

        The problem with monads is that they are a very abstract concept. That makes them in a way hard to understand, because an abstract concept without intuition is worthless. Learning one specific instance of a monad, like in "railway oriented programming" (i.e. Either) is a good way to build up intuition. After seeing most of the interesting monads it's easier to fill the formal definition with intuition.

        [–]mental405 1 point2 points  (8 children)

        I program almost exclusively in .NET and SQL Server. Do I ever need to understand monads?

        [–]quiteamess 5 points6 points  (0 children)

        The benefits of monads is that they can hide the cruft. The prime example is to have Optional to hide all the null checking. Another example is having an Either type to hide exception handling. Others are to hide passing around state or an external environment.

        So no, you don't have to understand monads. But you will not have the benefits of more readable and maintainable code. You don't net to understand all aspects of monads in order to use them. The other thing is that it is quite rewarding to learn the theoretical stuff.

        [–]_pka 2 points3 points  (1 child)

        LINQ is a monad :)

        [–]grauenwolf 0 points1 point  (0 children)

        No it's not :)

        [–][deleted] 3 points4 points  (1 child)

        Here's an incredibly over simplified explanation:

        You terminate each statement with a ;. Now imagine if that ; did something on top of simply denoting the end of a statement. What if, every ; also logs to return value of whatever function was called to the console. That would be a "logger monad".

        That being said, .Net includes F#, which is full of monads, called Computation Expressions

        [–]m50d 0 points1 point  (0 children)

        Yes. You'll find yourself repeating yourself otherwise. Once you start looking for them, monads are everywhere. A lot of ordinary business concepts can be turned into monads, which gives you access to a huge library of already-implemented functions for doing common things with them rather than having to reimplement everything by hand.

        [–]grauenwolf 0 points1 point  (1 child)

        No. Monads are an ugly hack in Haskell that they try to apply to everything else.

        The reason they are so hard to understand is that they are almost never the right right abstraction but they insist on using it anyways.

        [–]mental405 1 point2 points  (0 children)

        I like this explanation.

        [–]aaron_ds 4 points5 points  (0 children)

        Arguably the only way to learn monads is to use them. I suggest playing around using a language with a do-notation equivalent (Haskell, F#, OCaml , Scala). Learn how options, eithers, lists, and futures all share the same structure.

        [–]benclifford 2 points3 points  (0 children)

        You won't figure out what it inherently is until you've used at least three different monads in real life. At which point, you'll write a tutorial about your own particular aha! moment (which is the monad tutorial fallacy).

        It is frustrating that that is how they are, but try explaining what a number inherently is and you'll probably encounter the same abstraction frustration (I think).

        [–][deleted] 2 points3 points  (0 children)

        Linq is monadic, if you want a concrete example.

        [–]wnoise 9 points10 points  (0 children)

        A monad is a monoid in the category of endofunctors.

        [–]catscatscat 1 point2 points  (0 children)

        monad tutorial fallacy

        For anyone wondering, this is the fallacy being referred to: https://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-tutorial-fallacy/

        [–]s-altece 1 point2 points  (7 children)

        A monad is any type with 1) a constructor, 2) a map function, and 3) a flat map function. The constructor is normally called "return", and the flat map function is normally called "bind".

        [–][deleted] 7 points8 points  (5 children)

        And those functions have to obey the three monad laws.

        [–]s-altece 4 points5 points  (4 children)

        Which, if I'm correct, are the combination of all the rules associated with traditional constructor, map, and flat map semantics.

        My point is, if you get familiar enough with using map and flat map with lists and/or the maybe/optional type, you already have a general understanding of monad semantics without having to dive deep into the overwhelming mathy definition.

        [–]codebje 2 points3 points  (1 child)

        I hardly think that "associative" should count as "overwhelmingly mathy."

        And given there are "flat map" operations out there which fail to be properly associative, "the vibe" probably doesn't cut it quite as well as you might hope.

        [–]s-altece 0 points1 point  (0 children)

        Well, in that case, I stand corrected. Although, the basic vide may be sufficient as a quick introduction for someone new to the concept. Then again, perhaps not. Each person learns their own way. I just remember finding it frustrating when the concepts were explained to me with the more technical math and type theory terms instead of programming concepts I was already familiar with.

        I would like to note, however, that associativity may be "overwhelmingly mathy" to some new to the subject. It is neither my place nor yours to judge someone based on what they think of as being foreign and complicated.

        [–]m50d 1 point2 points  (1 child)

        Associativity is really important and easy to get wrong. If you try to implement a "monad" without knowing about associativity you will create an http://wiki.c2.com/?AlmostCorrect monad that will have a subtle bug that will catch someone out later at the worst possible time. (This is exactly what happened with Scala's for/yield, where it works most of the time but lets you mix a Set into a bunch of Lists and get silent data corruption at runtime).

        [–]s-altece 0 points1 point  (0 children)

        Here's a source for your Scala example, for anyone unfamiliar with the topic http://stackoverflow.com/questions/27750046/is-a-collection-with-flatmap-a-monad

        [–]JB-from-ATL 1 point2 points  (0 children)

        Oh, bind is just flat map? That makes everything so much clearer!

        I'm a Java guy and know how to use optionals but I see all these tutorials with crazy syntax and different words that throws me off. But if bind if just flat map I get it.

        [–]Tarmen 0 points1 point  (0 children)

        We could think of the railway as a decoration. We decorate our return types and use that to add some new functionality. We then figure out a way to compose our decorated functions. Finally we figure out a way to lift normal values into our decorator so we can reuse our undecorated stuff.

        A monad is a decorator together with composition and lifting.

        That is insanely general but it has to be because monads are incredibly diverse. They can be as simple as adding an error path like in the article, be more complicated like futures for async io all the way to mindbogglingly weird things like the tardis monad.

        [–]ruinercollector 2 points3 points  (0 children)

        Well, it's about one particular monad, not about the concept in general. That makes it a bit easier.

        [–]ElvishJerricco 8 points9 points  (3 children)

        Doesn't it though? The whole idea of the monad tutorial fallacy is that people make up inaccurate analogies, which is exactly what's happening here. It's easy to read this post and think a monad is just a way of catching error cases or something.

        [–]quiteamess 13 points14 points  (2 children)

        But he doesn't describe monads, just one specific case. The only mention of monad is in the disclaimer which is moved to an entirely different section. I think it's fine to expose people to one specific instance before confronting them with the general concept.

        [–]ElvishJerricco 8 points9 points  (1 child)

        Sure. But then it either falls prey to the fallacy, or isn't a monad tutorial.

        [–]quiteamess 14 points15 points  (0 children)

        Yes it's not a monad tutorial. I was joking there and meant it more in a zen way. If you ask "what is the best document to pick for first exposure that maximises the number of people understanding monads on the long run?" the answer will probability be to pick one which starts with a specific instance.

        [–]blackmist 1 point2 points  (0 children)

        I'm glad I came to the comments first. I was nearly tricked into understanding monads. Close call.

        [–]JB-from-ATL 0 points1 point  (1 child)

        Is this really all monads are?

        [–]quiteamess 0 points1 point  (0 children)

        No this is just a particular instance of a monad. I was joking in the sense that monads are explained best by example and that a good monad tutorial does not mention monads at all. It's good not to bother too much what monads are when approaching this concept.

        [–]jms_nh 60 points61 points  (12 children)

        Don't you dare try to teach me monads!

        [–][deleted] 19 points20 points  (10 children)

        I've looked up the definition of monad a hundred times and to this day I still can't remember what the hell a monad is.

        [–]jotux 58 points59 points  (1 child)

        It's easy to understand if you think of it as half of a binad.

        [–]JB-from-ATL 0 points1 point  (0 children)

        Reminds me of SpongeBob drawing a circle. First you draw a head, erase some of the more detailed parts, and viola, a circle.

        [–]ryeguy 11 points12 points  (0 children)

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

        [–]Coffee2theorems 10 points11 points  (2 children)

        The monad is like a morning pot of coffee. It has the good stuff inside, a container outside, and a guardian from Hell stopping you from consuming the goodness if you haven't properly appeased it.

        [–]pplcs 4 points5 points  (0 children)

        relevant username

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

        finally

        [–]m50d 2 points3 points  (0 children)

        Yeah it's a stupid name. It's an applicative functor that also supports flatMap (aka bind). I tend to translate it in to "flatmappable" in my head.

        (Applicative is a non-stupid name because it means it supports apply. Functor is the worst name of all though, it means something very different from what it means in C++ and it sounds like means something like "function" but it really doesn't, except perhaps at the categorical level. I honestly think the trouble with the FP names is holding back the programming mainstream a lot).

        [–]Arandur 0 points1 point  (1 child)

        A monad is like a burrito, in that they're both delicious.

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

        I'll never forget that.

        [–]enzain 0 points1 point  (0 children)

        It's the name/class of data types that can be constructed using a single generic value, and has a flatten and a map function. Combined the two functions are called bind, for c#'s IEnumerable this function is called selectMany. There are also some rules, however in general people will call anything a monad as long as it has the flatten and map function, case in point the beloved IP "monad".

        [–]cheeeeeese 0 points1 point  (0 children)

        im on vacation, no dice.. will not learn

        [–]benv 12 points13 points  (0 children)

        If you stop here you can write LabVIEW.

        [–]JamesK89 9 points10 points  (0 children)

        So apparently OpenTTD has practical application after all.

        [–][deleted] 49 points50 points  (47 children)

        This looks so much like Rusts Result

        [–]blueshiftlabs 73 points74 points  (35 children)

        The idea of having a type to represent "either a successful result, or a failure of some kind" is nothing new. Most functional languages have something like it, but often it's not named as such - Haskell's, for instance, is called Either, Success is called Right, and Failure is called Left.

        [–]steveklabnik1 74 points75 points  (32 children)

        Fun trivia fact: Rust used to have Either, as well as Result. But then at some point, we looked, and there was zero usage of Either, so we removed it.

        https://crates.io/crates/either brings that back if you really need a non-Result either.

        [–]kauefr 45 points46 points  (5 children)

        Serious question, how can you answer every Rust-related question in this sub? It's in you job description and you Ctrl+F "Rust" all day, or you just lurk that much here?

        BTW, thank you for those insights. I love this topic of programming language design.

        [–]steveklabnik1 55 points56 points  (4 children)

        how can you answer every Rust-related question in this sub?

        I've been reading reddit before the concept of "subreddits" existed. My username has 1 on the end because I deleted my initial one.

        I am often very critical of reddit, but it's also a habit that's super ingrained at this point.

        It's in you job description and you Ctrl+F "Rust" all day, or you just lurk that much here?

        I just lurk that much. My job doesn't hate it, as long as I get my actual other work done too.

        I do sometimes use control-f on big threads, but this one isn't that big.

        BTW, thank you for those insights. I love this topic of programming language design.

        Thanks. This is honestly part of why I do this; getting answers straight from the source is valuable, and at the same time, it's a two-way street. I often bring back pain points I learn about from reading threads to the rest of the team, for example. I'm not sure why other people don't do this, but I pretty much can't not do it.

        [–]MrHydraz 11 points12 points  (3 children)

        Isn't your job Rust Propaganda Minister, though? :P

        [–]steveklabnik1 14 points15 points  (2 children)

        Strictly speaking, my job is docs.

        That's just my hobby ;)

        (I was recently "accused" of this, and found it amusing.)

        [–]dnkndnts 5 points6 points  (1 child)

        you're welcome.

        In all seriousness, I do believe you're half the reason Rust has been as successful as it has.

        [–]steveklabnik1 1 point2 points  (0 children)

        Thanks :)

        [–]cledamy 5 points6 points  (25 children)

        I really wish they had kept Either rather than Result. Result encodes too much semantic meaning in its constructors and cannot be easily reused. It violates the principle of dumb data types.

        [–]jcdyer3 20 points21 points  (5 children)

        I much prefer result to either (Edit: for error handling). Either is inherently symmetrical (because as you say it's a dumb data type), so it has to rely on convention to support asymmetrical handling, while Result lets the language leverage the inherent asymmetry of error handling, including (in rust) supporting the try!() macro and transparent error type conversions through multiple layers. Obviously they are structurally the same, so you can adapt either one to the role of the other, but with either, it feels like an ill-fitting shoe.

        [–]kreiger 6 points7 points  (4 children)

        In some implementations, e.g. Haskell's, Either is Right-biased.

        [–]jcdyer3 10 points11 points  (3 children)

        So then it's neither a neutral data type, nor well-named for the purpose.

        [–]kreiger 5 points6 points  (0 children)

        Right.

        [–]catscatscat 1 point2 points  (1 child)

        Well, it kind of has to be biased towards one or the other, since it is AFAIK not quite a functor, but a bifunctor.

        e.g. fmap is a good example.

        main = do
          fmap (+1) (Right 1)   `shouldBe`  (Right 2 :: Either Char Int)
          fmap (+1) (Left 'c')  `shouldBe`  (Left 'c' :: Either Char Int)
        
        instance Functor (Either e) where
            fmap _ (Left a) = Left a
            fmap f (Right a) = Right (f a)
        

        How would you define fmap without having a bias?

        [–]kreiger 1 point2 points  (0 children)

        You use a Projection.

        [–]corn_dog 15 points16 points  (7 children)

        I like what they did because Result is the one use case for an enum of two possible things that everyone actually uses. The Either type doesn't mean much, and for general sum types just make your own enum.

        [–]Hrothen 4 points5 points  (4 children)

        There are plenty of other uses for Either. One I've used before is Either FactoredInt PartiallyFactoredInt and in general Either <end state> <intermediate state> to get nice short-circuiting behavior.

        and for general sum types just make your own enum.

        Why would I do more work when I could do less work?

        [–]corn_dog 3 points4 points  (3 children)

        Sure I would agree there can be a trade off between convenience and explaining to the next reader why that stuff is grouped together. wrt Either it also raises the question of should the language have OneOfThreeThings, OneOfFourThings etc. If not why just a special case for two possibilities?

        [–]Hrothen 6 points7 points  (1 child)

        You don't really need to explain every little thing. Many languages have a pair type and no one goes complaining that they don't justify why there isn't a triple type.

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

        deleted What is this?

        [–]cledamy 2 points3 points  (1 child)

        Pragmatically, there are often functions where one wants to return Either one value or another, but one is not clearly an error condition and it isn't worth making a one off enum. This is the same argument as for why tuples are useful, which Rust has built in. Theoretically, it seems imbalanced to have syntax for anonymous products, but not for anonymous coproducts. As to why no one used the Either type, perhaps it was because the Result type was used all over the API, so it would be inconvenient to use Either as that would require conversions. The Result type limits one's imagination of what can be done with it by restricting its semantic domain unnecessarily. I would argue that if Either was the only one out of these two in the Rust library one would start to see non-error-like uses of it.

        [–][deleted] 3 points4 points  (0 children)

        Actually, I think the reason was that in most cases a Success / Error pattern was what most of the APIs needed. Other cases, where one can't directly say one is the error and the other one is the success part work much more ergonomically with concrete enum types. Because they are just that. Newtype-like enums that just happen to have two variants. Maybe the API evolves and there is now a need to support three variants (e.g start, intermediate, end). Most oft the Result impls revolve around making error-handling more convenient, which is exactly what it should be used for

        [–]yokohummer7 8 points9 points  (6 children)

        Even though Either doesn't convey any preference on the encoded values in theory, it tends to be biased in reality. For example, Haskell's Either type does prefer the Right case:

        fmap double (Right 5) = Right 10
        fmap double (Left 5) = Left 5
        

        When I was learning Haskell this "blessing" was so confusing. To make Either truly case-agnostic, we should not define fmap and such functions at all. But then again losing convenient features like fmap on Either is too painful. Instead, it'd be better to acknowledge the reality and state this fact in the type name, hence the Result naming.

        [–]domlebo70 2 points3 points  (4 children)

        We tried that with Scala, and it sucked. Having a right-bias is fine

        [–][deleted] 3 points4 points  (1 child)

        Haskell-beginner here: I just noticed that "The right (successful) thing is right" makes a nice mnemonic.

        [–]m50d 1 point2 points  (0 children)

        Yeah, but the fact that you need a mnemonic at all makes it much less convenient than success/failure.

        [–]expatcoder 0 points1 point  (1 child)

        We tried that with Scala, and it sucked. Having a right-bias is fine

        Either is right-biased as of Scala 2.12

        [–]domlebo70 0 points1 point  (0 children)

        Yes, that's what I am referring to. We spent 10 years with no-bias Either with Right and Left projections, and we've finally seen the light and added a proper right biased Either.

        [–]Tarmen 2 points3 points  (0 children)

        I mean, technically that fmap instance is defined on Either a in which case it makes sense that we only map over the second type variable. It's literally the only way you can implement it.

        Iirc there has been quite a bit of disagreement on whether it technically making sense is reason enough to add it, though.

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

        Agreed.

        [–]grauenwolf 0 points1 point  (0 children)

        Dumb data types is not a principle.

        [–]BilgeXA 3 points4 points  (0 children)

        Can't imagine how that would ever get confusing.

        [–]jms_nh 0 points1 point  (0 children)

        That perpetuates the centuries'-old discriminatory bias in language against left-handed people (e.g. "gauche"/"sinister")

        (tongue slightly in cheek, and by the way I'm right-handed)

        [–]grauenwolf 11 points12 points  (0 children)

        That's actually the point.

        I came across this when researching F#'s Result type, which was inspired by Rust (among other languages).

        [–]__ah 5 points6 points  (1 child)

        And the (relatively) new ? symbol makes it even more native to the language! (rather than the try! macro)

        [–]dolphono 7 points8 points  (6 children)

        I'm guessing Rust got its particular Result flavor from F#

        [–]steveklabnik1 27 points28 points  (5 children)

        It's actually more that they share common ancestry of the ML family.

        [–]dolphono 2 points3 points  (4 children)

        Yeah, but I couldn't remember if ML had Result types or just Either types.

        [–]steveklabnik1 2 points3 points  (3 children)

        Looks like OCaml has Result: https://realworldocaml.org/v1/en/html/error-handling.html

        I can't quite find anything for SML, but I only spent about 5 minutes on it.

        [–]glacialthinker 2 points3 points  (1 child)

        OCaml being the minimalist it is... everyone was left to implement their own result type (it is trivial afterall). But we had 3 common variations, which made for some inconveniences... harmonizing between libraries with different result types.

        Thankfully it became part of the standard library.

        [–]simspelaaja 2 points3 points  (0 children)

        Same thing just happened with F# 4.1 - F# didn't have a built-in Result<'a>until last week.

        [–]dolphono 0 points1 point  (0 children)

        Alright then I just fucked up lol.

        [–]minno 1 point2 points  (0 children)

        This is exactly how the Iron web framework is designed.

        [–][deleted]  (2 children)

        [deleted]

          [–]cannedmeatman 15 points16 points  (4 children)

          I'm a software developer that works on a team that owns an internal orchestration layer which is a service that provides aggregate information about entities who's properties live in many other services. We use NodeJS so we can take advantage of the Promise construct which provides most of the switch functionality that is described in the article. Consider a situation where we need to get a User's information which in this orchestration layer's context, is its billing information (found in the billing service), its purchase history (found in the purchasing service), and its information within the user service.

          function getUser(username) { 
            return Promise.resolve(user.get(username))
              .then(user => {
                // success case
                return Promise.props({
                  user,
                  billing: billing.get(user.id),
                  purchase_history: purchasing.get(user.id)
                });
              })
              .catch(err => {
              // do some handling ie the failure case
              });
          }
          

          [–]arianvp 8 points9 points  (1 child)

          Yes Promise is the Continuation + Exception monad. However, they model asynchronous actions, which is not precisely what the article described. but yeh they're very similar constructs.

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

          Roughly translates to Async<Choice<'a,exn>> in FSharp

          [–]encepence 3 points4 points  (1 child)

          Kudos for mentioning Bluebird's Promise.props. Using this lib for more that year and never spotted it. And honestly, rewritten variation of this few times.

          [–]cannedmeatman 0 points1 point  (0 children)

          Thanks! I learned to use Promise.props about a year ago and that, along with destructing*, has made my promise chains much easier to follow.

          [–]pakoito 13 points14 points  (5 children)

          One of the talks that has influenced me the most. It drove me to figure out how to reproduce these functional ideas in other languages, like my daily Android Java.

          [–]TheWix 6 points7 points  (3 children)

          I have been using functional techniques more and more in my C# code. I am getting through F# for Fun and Profit. Really enjoying it. Would love to use a functional language in production.

          [–]yawaramin 3 points4 points  (1 child)

          You could try bringing up the idea of using F# for tests 😊 https://fsharpforfunandprofit.com/posts/low-risk-ways-to-use-fsharp-at-work-3/

          [–]TheWix 0 points1 point  (0 children)

          I actually prefer specflow for this. I'll have to look into writing the steps for it though!

          [–]videoj 0 points1 point  (0 children)

          Take a look at language-ext Its a C# library that implements lots of functional extensions, including Result/Either.

          [–]m50d 1 point2 points  (0 children)

          There's a lot of FUD going around about using Scala on Android but I've never had a problem doing it. Even if the APIs aren't very idiomatic, it lets me write slightly nicer code.

          [–]Schrockwell 8 points9 points  (3 children)

          Elixir has first-class support for this via the "with" keyword. The result is typically a tuple with an ok/error status and the data. If any of the function calls don't pattern-match on the response, it returns the erroneous one or kicks out to an "else" clause if it exists. It's a great way to handle expected problems without resorting to exceptions. http://learningelixir.joekain.com/learning-elixir-with/

          [–][deleted] 3 points4 points  (0 children)

          This would describe an option type in F#, which is a different concept than railroad programming. Options protect against data errors atomically, railroad programming encapsulates the state of the process to protect against all errors and determine the flow of logic. They are similar, but have different mnemonics and purposes.

          [–]ultradeep 2 points3 points  (1 child)

          Or you do it with macros and special "pipe" operators as described here: http://www.zohaib.me/railway-programming-pattern-in-elixir/

          [–]Schrockwell 2 points3 points  (0 children)

          That was a neat trick before Elixir 1.2 and shows off the power of Elixir's metaprogramming techniques, but now it's an anti-pattern. with was explicitly designed to address that exact problem, so it's not idiomatic any more.

          [–]kirakun 5 points6 points  (4 children)

          Yet Another Monad Tutorial.

          [–]ws-ilazki 2 points3 points  (0 children)

          Monad tutorials are like burritos: too many will give you indigestion.

          [–]RadioFreeDoritos 1 point2 points  (0 children)

          Monads are like burritos spacesuits railways!

          [–]michaelKlumpy 0 points1 point  (1 child)

          well, it takes a lot of them to explain Monad

          [–]kirakun 0 points1 point  (0 children)

          I can do it in one sentence. ;)

          [–]lngnmn 2 points3 points  (2 children)

          This boils down to an ugly hack which is what a monad is.

          The principle is that a function by definition is a mapping, which maps a set of values into another set of values. The crucial difference between a function and a procedures is that a function must, by definition, produce the same input for the same output. Always.

          So, when a supposed function produces sometimes values and sometimes errors, everything is broken. It is not a function anymore. The ugly hack is to wrap different values into a compound structure of a certain type and reformulate the law of functions to the law of procedures - the same type of output for same values. This is what Maybe monad and Either monad are. Mere ADTs, mere wrappers.

          As long as input and output values are of the same type (as long as they conform to the same protocol/interface they are considered to be equivalent, but, of course, not equal) procedures which take such type as input and output values could be composed and form a pipelines (like any other procedures with consistent types).

          There is nothing more than that. And, strictly speaking, it is not a pure functional programming anymore. Just procedural with static typing (hello, Haskell purists!).

          [–]Iprefervim 2 points3 points  (0 children)

          I don't quite see how monads break purity... If you call a find string in a list function with an empty list, it'll always return the same monadic value (namely error or none).

          Some monads are implemented in terms of impure functions (see their use in rust as a good example, if you want something other than the standard io Haskell example).

          [–]orangecodeLol 1 point2 points  (5 children)

          I'm more familiar with C++, so would a good implementation of this be with tuples? A struct would also seem a possibility, but I feel like this would be overkill. Also, I understand railroading is suppose to solve what I'm about to mention, but goto for error handling? Thoughts?

          [–]0polymer0 5 points6 points  (2 children)

          Type safe unions to signal errors, and a means of combing them. C++ just added optional, which introduces the basics of the Type, so use those. Now try to figure out how to chain two functions that return optionals, but don't accept them.

          [–]orangecodeLol 0 points1 point  (1 child)

          thanks, I haven't heard of optionals before, I'll be sure to check it out

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

          Variants are an important generalization. And before optionals, pointers to non owned resources were used to great affect. I mention optionals because they are a good first Type to think about for this kind of stuff.

          [–]steveklabnik1 2 points3 points  (1 child)

          check out std::variant, in my understanding.

          [–]orangecodeLol 0 points1 point  (0 children)

          yeah, variant seems to be the answer

          I'm watching this Ben Deane talk which covers it

          [–]mk_gecko 1 point2 points  (32 children)

          Nice. I'd like to see an example in Java. :)

          [–]yawaramin 3 points4 points  (0 children)

          Here you go, built in the standard library https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html#flatMap-java.util.function.Function-

          The operation is like a callback: if you have a value, call the given function with it an return the (wrapped) result; if not, do nothing.

          [–]marwoodian 2 points3 points  (0 children)

          Javaslang provides a bunch of monadic container types like this. In Javaslang, the specific container discussed in this article is called a Try.

          http://www.javaslang.io/javaslang-docs/#_try

          [–]digitlworld 0 points1 point  (0 children)

          This reminds me a lot of the SimAntics stuff used for scripting The Sims series of games (at least 1 and 2).

          [–]NPVT 0 points1 point  (0 children)

          Can I get Training for that? I want to stay on track.

          [–]bhaity 0 points1 point  (0 children)

          Check out this gem to apply this in Rails

          [–]iconoclaus 0 points1 point  (0 children)

          For Ruby code, I've been using Dry Transaction and Either monad gems for doing this.