Alex Rivera | Logout

Function as an Instance of Monad

Asked 2012-10-26T02:37:17.483
9

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

Edit
Report

1 Answer

7

It's perhaps easier to understand this monad by looking at what join does, since a monad can equivalently be defined using fmap and join instead of >>=.

The general form of join has the type Monad m => m (m b) -> m b, so it takes a "two-layer" monadic value and crunches it down to one layer.

With the function monad, m ~ (a ->), so join has the type (a -> a -> b) -> (a -> b) so it takes a function of two arguments and returns a function that only takes one.

join :: (a -> a -> b) -> (a -> b)
join f = \x -> f x x

As you can see, it just duplicates the argument.

Similarly, fmap on functions is just function composition, and return is const.

I think it's much easier to understand this way than trying to make sense of >>=.

answered 2012-10-26T03:10:24.780

Your Answer