I am having difficulty understanding how a function can be a monad.
Function (->) r is a monad according to a declaration in Control.Monad.Instances:
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
Even what Miran Lipovača says about it makes me confused:
The implementation for
>>=seems a bit cryptic, but it’s really not
all that. When we use>>=to feed a monadic value to a function, the
result is always a monadic value. So in this case, when we feed a
function to another function, the result is a function as well. That’s
why the result starts off as a lambda. All of the implementations of
>>=so far always somehow isolated the result from the monadic value and then applied the function f to that result. The same thing happens
here. To get the result from a function, we have to apply it to
something, which is why we do(h w)here to get the result from the
function and then we apply f to that. f returns a monadic value, which
is a function in our case, so we apply it to w as well.
The type signature of (>>=) is this:
(>>=) :: m a -> (a -> m b) -> m b
So I take that h is typed as m a and f as (a -> m b). If a function is m a, does it return an a type value? or does it return something else taking an a type?
If the non-monad value of h is fed to f, then we get:
f (h w)
Looks fine. Since f is a function and has taken its sole argument, it is already a value, no? Since it’s a monadic function the value is also a monadic value. Why then does it need another value w? Doesn’t feeding w to f something make it non-monadic, i.e., it is not a function any more, no? I also cannot understand why f something and h take the same argument w and return different value types (m a and m b).
First, here’s the type of
(>>=):Now, with
mspecialized to((->) r):Rewritten with all the function arrows infix:
Removing some superfluous parentheses:
At which point it should be much easier to see what’s going on: the third argument (of type
r) is given to the first argument to get something of typea, then both that result and the third argument are given to the second argument to get a final result of typeb.So,
((->) r)as aMonadrepresents an extra function argument to every value in that monad, and when monadic values are combined the single “extra” argument is duplicated and given to each input value. Essentially, this creates a “read-only global environment” for monadic values. This interpretation is provided explicitly as theReadermonad, which is just a wrapper around((->) r).