How to detect a Monad?

后端 未结 4 1174
南旧
南旧 2021-02-13 03:32

Many of us don\'t have a background on functional programming, and much less on category theory algebra. So let\'s suppose that we need and therefore create a generic type like<

4条回答
  •  清酒与你
    2021-02-13 04:32

    A big step forward for me in my understanding of monads was the post Monads are Trees with Grafting. If your type looks like a tree, and the t values appear at the leaves, then you may have a monad on your hands.

    Simple examples

    Some data types are obviously trees, for example the Maybe type

    data Maybe a = Nothing | Just a
    

    which either has a null leaf, or a leaf with a single value. The list is another obvious tree type

    data List a = Nil | Cons a (List a)
    

    which is either a null leaf, or a leaf with a single value and another list. An even more obvious tree is the binary tree

    data Tree a = Leaf a | Bin (Tree a) (Tree a)
    

    with values at the leaves.

    Harder examples

    However, some types don't look like trees at first glance. For example, the 'reader' monad (aka function monad or environment monad) looks like

    data Reader r a = Reader { runReader :: r -> a }
    

    Doesn't look like a tree at the moment. But let's specialize to a concrete type r, for example Bool --

    data ReaderBool a = ReaderBool (Bool -> a)
    

    A function from Bool to a is equivalent to a pair (a,a) where the left element of the pair is the value of the function on True and the right argument is the value on False --

    data ReaderBool a = ReaderBool a a
    

    which looks a lot more like a tree with only one type of leaf - and indeed, you can make it into a monad

    instance Monad ReaderBool where
        return a = ReaderBool a a
        ReaderBool a b >>= f = ReaderBool a' b'
          where
            ReaderBool a' _ = f a
            ReaderBool _ b' = f b
    

    The moral is that a function r -> a can be viewed as a big long tuple containing many values of type a, one for each possible input - and that tuple can be viewed as the leaf of a particularly simple tree.

    The state monad is another example of this type

    data State s a = State { runState :: s -> (a, s) }
    

    where you can view s -> (a, s) as a big tuple of values of type (a, s) -- one for possible input of type s.

    One more example - a simplified IO action monad

    data Action a = Put String (Action a)
                  | Get (String -> Action a)
                  | Return a
    

    This is a tree with three types of leaf -- the Put leaf which just carries another action, the Get leaf, which can be viewed as an infinite tuple of actions (one for each possible String input) and a simple Return leaf that just carries a single value of type a. So it looks like it might be a monad, and indeed it is

    instance Monad Action where
      return = Return
    
      Put s a  >>= f = Put s (a >>= f)
      Get g    >>= f = Get (\s -> g s >>= f)
      Return a >>= f = f a
    

    Hopefully that's given you a little bit of intuition.

    Thinking of monads as trees, the return operation as a way of getting a simple tree with one value, and the >>= operation as a way replacing the elements at the leaves of the tree with new trees, can be a powerful unifying way to look at monads.

提交回复
热议问题