haskellfunctional-programmingmonadspointfree

How to use (->) instances of Monad and confusion about (->)


At different questions I've found hints in comments concerning using the (->) instance of Monads e.g. for realizing point-free style.

As for me, this is a little too abstract. Ok, I've seen Arrow instances on (->) and it seems to me, that (->) can be used in instance notations but not in type declarations (that would alone be stuff for another question).

Has anyone examples using (->) as instance of Monad? Or a good link?

Sorry if this question may already have been discussed here, but searching for "(->) Monad instance" gives you many many hits as you can imagine ... since nearly every question about Haskell somewhere involves (->) or "Monad".


Solution

  • For a given type r, the function of type r -> a can be thought of as a computation delivering an a using an environment typed r. Given two functions r -> a and a -> (r -> b), it's easy to imagine that one can compose these when given an environment (again, of type r).

    But wait! That's exactly what monads are about!

    So we can create an instance of Monad for (->) r (*) that implements f >>= g by passing the r to both f and g. This is what the Monad instance for (->) r does.

    To actually access the environment, you can use id :: r -> r, which you can now think of as a computation running in an environment r and delivering an r. To create local sub-environments, you can use the following:

    inLocalEnvironment :: (r -> r) -> (r -> a) -> (r -> a)
    inLocalEnvironment xform f = \env -> f (xform env)
    

    This pattern of having an environment passed to computations that can then query it and modify it locally is useful for not just the (->) r monad, which is why it is abstracted into the MonadReader class, using much more sensible names than what I've used here:

    http://hackage.haskell.org/packages/archive/mtl/2.0.1.0/doc/html/Control-Monad-Reader-Class.html

    Basically, it has two instances: (->) r that we've seen here, and ReaderT r m, which is just a newtype wrapper around r -> m a, so it's the same thing as the (->) r monad I've described here, except it delivers computations in some other, transformed monad.

    (*) (->) r might look funny at first, but this is Haskell syntax for partially applying the two-parameter type constructor (->) to the first type argument r, i.e. it means something like r -> _ with the second argument not yet given. So (->) r a (or ((->) r) a) is the same as r -> a.