This isn’t needed for day-to-day use, but might help intuition:
What I described above is a possible way to implement a monad:
map : (a -> b) -> MyType a -> MyType b
unwrap : MyType (MyType a) -> MyType a
Combining those gives you
andThen : (a -> MyType a) -> MyType a -> MyType b
andThen fn myType =
myType -- `MyType a`
|> map fn -- gives you `MyType (MyType b)`
|> unwrap -- gives you `MyType b`
You still need something to create MyType out of an ordinary value:
wrap : a -> MyType a
After you have both wrap and andThen, you have a monad!
Implementing this for Maybe
As you can recall, Maybe is defined this way:
type Maybe a
= Nothing
| Just a
wrap
For defining wrap we have two options:
wrap1 : a -> Maybe a
wrap1 _ =
Nothing
wrap2 : a -> Maybe a
wrap2 value =
Just value
Which one to use? Well, there are “Monad laws” that say how the functions wrap and andThen have to work together. I won’t dive into this, but if you did, you would find wrap2 is the correct one 
andThen
We can define andThen ourselves directly:
andThen : (a -> Maybe b) -> Maybe a -> Maybe b
andThen fn maybeValue =
case maybeValue of
Nothing ->
Nothing
Just value ->
fn value
Or, we can go the map + unwrap way:
andThen : (a -> Maybe b) -> Maybe a -> Maybe b
andThen fn maybeValue =
maybeValue
|> map fn
|> unwrap
with map and unwrap defined below:
map
map : (a -> b) -> Maybe a -> Maybe b
map fn maybeValue =
case maybeValue of
Nothing ->
Nothing
Just value ->
Just (fn value)
Try to find the (two) differences from andThen!
unwrap
unwrap : Maybe (Maybe a) -> Maybe a
unwrap nestedMaybe =
case nestedMaybe of
Nothing ->
Nothing
Just maybe ->
maybe
So, these are the building blocks of monads. wrap and andThen. Monad is just a type and a set of functions on it that have a certain type and behave a certain way.
Note: In academic literature the names are sometimes a bit different (but I like the Elm ones more
)
-
map is called fmap
-
unwrap is called join
-
andThen is called bind or >>=
-
wrap is called return or pure