What is a monad?

前端 未结 30 1642
太阳男子
太阳男子 2020-11-30 13:39

Having briefly looked at Haskell recently, what would be a brief, succinct, practical explanation as to what a monad essentially is?

I have found most expla

30条回答
  •  夕颜
    夕颜 (楼主)
    2020-11-30 13:59

    Let the below "{| a |m}" represent some piece of monadic data. A data type which advertises an a:

            (I got an a!)
              /        
        {| a |m}
    

    Function, f, knows how to create a monad, if only it had an a:

           (Hi f! What should I be?)
                          /
    (You?. Oh, you'll be /
     that data there.)  /
     /                 /  (I got a b.)
    |    --------------      |
    |  /                     |
    f a                      |
      |--later->       {| b |m}
    

    Here we see function, f, tries to evaluate a monad but gets rebuked.

    (Hmm, how do I get that a?)
     o       (Get lost buddy.
    o         Wrong type.)
    o       /
    f {| a |m}
    

    Funtion, f, finds a way to extract the a by using >>=.

            (Muaahaha. How you 
             like me now!?)       
        (Better.)      \
            |     (Give me that a.)
    (Fine, well ok.)    |
             \          |
       {| a |m}   >>=   f
    

    Little does f know, the monad and >>= are in collusion.

                (Yah got an a for me?)       
    (Yeah, but hey    | 
     listen. I got    |
     something to     |
     tell you first   |
     ...)   \        /
             |      /
       {| a |m}   >>=   f
    

    But what do they actually talk about? Well, that depends on the monad. Talking solely in the abstract has limited use; you have to have some experience with particular monads to flesh out the understanding.

    For instance, the data type Maybe

     data Maybe a = Nothing | Just a
    

    has a monad instance which will acts like the following...

    Wherein, if the case is Just a

                (Yah what is it?)       
    (... hm? Oh,      |
    forget about it.  |
    Hey a, yr up.)    | 
                \     |
    (Evaluation  \    |
    time already? \   |
    Hows my hair?) |  |
          |       /   |
          |  (It's    |
          |  fine.)  /
          |   /     /    
       {| a |m}   >>=   f
    

    But for the case of Nothing

            (Yah what is it?)       
    (... There      |
    is no a. )      |
      |        (No a?)
    (No a.)         |
      |        (Ok, I'll deal
      |         with this.)
       \            |
        \      (Hey f, get lost.) 
         \          |   ( Where's my a? 
          \         |     I evaluate a)
           \    (Not any more  |
            \    you don't.    |
             |   We're returning
             |   Nothing.)   /
             |      |       /
             |      |      /
             |      |     /
       {| a |m}   >>=   f      (I got a b.)
                        |  (This is   \
                        |   such a     \
                        |   sham.) o o  \
                        |               o|
                        |--later-> {| b |m}
    

    So the Maybe monad lets a computation continue if it actually contains the a it advertises, but aborts the computation if it doesn't. The result, however is still a piece of monadic data, though not the output of f. For this reason, the Maybe monad is used to represent the context of failure.

    Different monads behave differently. Lists are other types of data with monadic instances. They behave like the following:

    (Ok, here's your a. Well, its
     a bunch of them, actually.)
      |
      |    (Thanks, no problem. Ok
      |     f, here you go, an a.)
      |       |
      |       |        (Thank's. See
      |       |         you later.)
      |  (Whoa. Hold up f,      |
      |   I got another         |
      |   a for you.)           |
      |       |      (What? No, sorry.
      |       |       Can't do it. I 
      |       |       have my hands full
      |       |       with all these "b" 
      |       |       I just made.) 
      |  (I'll hold those,      |
      |   you take this, and   /
      |   come back for more  /
      |   when you're done   / 
      |   and we'll do it   / 
      |   again.)          /
       \      |  ( Uhhh. All right.)
        \     |       /    
         \    \      /
    {| a |m}   >>=  f  
    

    In this case, the function knew how to make a list from it's input, but didn't know what to do with extra input and extra lists. The bind >>=, helped f out by combining the multiple outputs. I include this example to show that while >>= is responsible for extracting a, it also has access to the eventual bound output of f. Indeed, it will never extract any a unless it knows the eventual output has the same type of context.

    There are other monads which are used to represent different contexts. Here's some characterizations of a few more. The IO monad doesn't actually have an a, but it knows a guy and will get that a for you. The State st monad has a secret stash of st that it will pass to f under the table, even though f just came asking for an a. The Reader r monad is similar to State st, although it only lets f look at r.

    The point in all this is that any type of data which is declared itself to be a Monad is declaring some sort of context around extracting a value from the monad. The big gain from all this? Well, its easy enough to couch a calculation with some sort of context. It can get messy, however, when stringing together multiple context laden calculations. The monad operations take care of resolving the interactions of context so that the programmer doesn't have to.

    Note, that use of the >>= eases a mess by by taking some of the autonomy away from f. That is, in the above case of Nothing for instance, f no longer gets to decide what to do in the case of Nothing; it's encoded in >>=. This is the trade off. If it was necessary for f to decide what to do in the case of Nothing, then f should have been a function from Maybe a to Maybe b. In this case, Maybe being a monad is irrelevant.

    Note, however, that sometimes a data type does not export it's constructors (looking at you IO), and if we want to work with the advertised value we have little choice but to work with it's monadic interface.

提交回复
热议问题