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".
For a given type
r
, the function of typer -> a
can be thought of as a computation delivering ana
using an environment typedr
. Given two functionsr -> a
anda -> (r -> b)
, it's easy to imagine that one can compose these when given an environment (again, of typer
).But wait! That's exactly what monads are about!
So we can create an instance of Monad for
(->) r
that implementsf >>= g
by passing ther
to bothf
andg
. 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 environmentr
and delivering anr
. To create local sub-environments, you can use the following: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 theMonadReader
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, andReaderT r m
, which is just anewtype
wrapper aroundr -> 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.To define a monad for
(->) r
, we need two operations,return
and(>>=)
, subject to three laws:If we look at the signature of return for
(->) r
we can see its just the constant function, which ignores its second argument.
Or alternately,
To build
(>>=)
, if we specialize its type signature with the monad(->) r
,there is really only one possible definition.
Using this monad is like passing along an extra argument
r
to every function. You might use this for configuration, or to pass options way down deep into the bowels of your program.We can check that it is a monad, by verifying the three monad laws:
The final monad law:
follows by similar, easy equational reasoning.
We can define a number of other classes for ((->) r) as well, such as Functor,
and if we look at the signature of
we can see that its just composition!
Similarly we can make an instance of
Applicative
What is nice about having these instances is they let you employ all of the Monad and Applicative combinators when manipulating functions.
There are plenty of instances of classes involving (->), for instance, you could hand-write the instance of Monoid for (b -> a), given a Monoid on
a
as:but given the Monad/Applicative instance, you can also define this instance with
using the Applicative instance for
(->) r
or withusing the Monad instance for
(->) r
.Here the savings are minimal, but, for instance the @pl tool for generating point-free code, which is provided by lambdabot on the #haskell IRC channel abuses these instances quite a bit.