Posted on January 20, 2019

Let’s face it: all monad tutorials suck. So here’s another one*:

What is Monad?


The term “Monad” comes from mathematics or philosophy, which exact meaning is irrelevant to programming in haskell.

Here’s the synopsis, but you really don’t need to read it:

A monad is a special case of a monoid.
A monoid is a mathematical structure: Set Theory describes it as a (set of values + some operator + identity element).
While Category Theory describes how it composes with other structures. Thus, (idea of) monad is related (loosely) to the (idea of a) function, defined over a set of elements, while identity element is required for mathematical consistency, which can be composed with other functions in a certain way.

Why bother giving such a fancy explanation for something which looks awfully like an ordinary function then?

Such interpretation of (the idea of) a function comes with a bonus from mathematics, as an algebra, allowing various code guarantees as well as ‘mathematically correct’ composability with other abstractions, which come with their own algebras and guarantees as well as ‘‘mathematically correct’… ad infinitum, while lambda calculus + syntactic sugar exposes it in haskell in the form of a Monad. For further reference: Set Theory and Category Theory.

It’s really a very basic and general idea, there’s not much to it, but it’s fleeing simplicity may feel like it’s hard to put a finger on:
It’s a value + sideffect.
It’s a way to sequence things together.
It’s a powerful building-block to write programs.
It’s the biggest haskell PR fail.
It’s just a monoid in the category of endofunctors.
It’s a burrito.

Why Monad?

Here’s what it means in practice: The infamous >>= helps us pass non-monadic values to functions without leaving a monad. In case of the Maybe monad, the monadic aspect is the qualifier that we don’t know with certainty whether the value will be… IO monad and do-notations gives as an elegant way to compose functions which arguably makes haskell the best language to write imperative programs.

In other words we sequence functional transformations of values in an intuitive way. It allows us to write complex functions in such a way, that instead of a hard to read mess of nested functions, we express it as a simple set of actions. We are syntactically chaining functions together.

regularBurrito :: ()
regularBurrito = ()
monadicBurrito :: IO ()
monadicBurrito =
  do
  ...stuff...
    return ()

and then, instead of

stomack = regularBurrito

you can write

stomack <- monadicBurrito

which is much more appropriate, is not it? The benefit becomes more obvious when we need to chain multiple functions over a value.

More examples of using Maybe monad with with and without sugar


-- | let x = foo in x + 3          corresponds to      (\x -> x + 3) foo
-- | x <- foo; return (x + 3)      to     foo >>= (\x -> return (x + 3))

displayResult :: Maybe Int -> String
displayResult mx = maybe "There was no result" (("The result was " ++) . show) mx   
              
-- | fromMaybe 0 (Just 1) - interesting example of Maybe and extracting
-- | values from Just   

add :: Maybe Int -> Maybe Int -> Maybe Int
add mx my =
  mx >>= (\x -> my >>= (\y -> return (x + y)))

-- | is equivalent to the following, using syntactic sugar:
add' :: Maybe Int -> Maybe Int -> Maybe Int
add' mx my = do
  x <- mx
  y <- my
  return (x + y)
  

main = undefined


Custom Monads, how?

(creating bespoke monadic types)

Standard programming interface allows us defining ‘our own monads’ (monadic types):

class Monad m where
  (>>=)  :: m a -> (  a -> m b) -> m b
  (>>)   :: m a ->  m b         -> m b
  return ::   a                 -> m a
  fail   :: String -> m a

Basically our custom type needs to implement this interface. In addition, it needs to satisfy the following laws, in order to be consistent with monadic algebra:

return a >>= k                  =  k a
m        >>= return             =  m
m        >>= (\x -> k x >>= h)  =  (m >>= k) >>= h

source

TODO : add a concrete example of a custom type, which is not Maybe or IO


Once we’ve done that, i.e. once we’ve guaranteed that our new type is monadic, we can use all the monadic goodies, e.g. >>=, do, <-, Monad Transformers, etc.


* this is not a monad tutorial


P.S. I probably stole bits and pieces from somebody, so if you need a credit or think that I lied somewhere and there should be a correction, please, feel free to ping me.

comments powered by Disqus