7

In the following instance of Monad:

instance Monad ((->) r) where
    return = const
    f >>= k = \ r -> k (f r) r

Is this forcing k to be a function of two parameters? And if so, why would you want to pass (f r) AND r to k?

GreenSaguaro
  • 2,968
  • 2
  • 22
  • 41
  • You might like the [Monads as Containers](https://wiki.haskell.org/Monads_as_containers) section on the reader monad (search for "reader"). – Daniel Wagner Sep 01 '15 at 21:00
  • Yes `k` is a function `a -> r -> b`. `r` is the only instance of `r` you have and `f r` is the only way to get an `a` so you don't have much choice. – Lee Sep 01 '15 at 21:02
  • possible duplicate of [How to use (->) instances of Monad and confusion about (->)](http://stackoverflow.com/questions/5310203/how-to-use-instances-of-monad-and-confusion-about) – Cactus Sep 02 '15 at 02:40

1 Answers1

9

Is this forcing k to be a function of two parameters?

Yes. Looking at the definition of Monad, we have

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

Substituting (->) r for m, we have

return :: a -> (->) r a
(>>=) :: (->) r a -> (a -> (->) r b) -> (->) r b

Now, (->) r a is just a weird syntax for r -> a, and similarly for the other cases, so we get

return :: a -> r -> a
(>>=) :: (r -> a) -> (a -> r -> b) -> r -> b

So we can see that indeed the second argument to >>= must be a function of (at least) two arguments.

Why? Because a function of two arguments is just a function taking one argument and returning a function of one argument, while the second argument to >>= should be a function taking one argument and returning a value of the monad's type constructor; for the function monad, this value will be a function. Hence the second argument to >>= will be a function of two arguments.

[W]hy would you want to pass (f r) AND r to k?

Partly because it makes the (->) r type fit the uniform structure of a Monad, which is useful for lots of reasons.

Partly k doesn't know which function f you're using. That means that, from k's perspective, the two arguments f r and r really are independent --- k can't calculate one from the other.

Consider this function:

-- | 'f' takes two numbers and adds them together
f :: (->) (Int, Int) Int
f = fst >>= \ n0 -> snd >>= \ n1 -> return (n0 + n1)

The function \ n0 -> snd >>= \ n1 -> return (n0 + n1) doesn't care where its argument comes from, or in particular that its argument is the first component of the input. So it needs both the argument n0 and the full input.

Jonathan Cast
  • 4,569
  • 19
  • 34