I learned that Monad.Reader is actually an encapsulation of a function, namely:
newtype Reader r a = Reader { runReader :: r -> a }
Which is made an instance of Monad,
instance Monad (Reader r) where
return a = Reader $ \_ -> a
m >>= k = Reader $ \r -> runReader (k (runReader m r)) r
In contrast, I knew that (->) is also a Monad,
instance Monad ((->) r) where
return = const
f >>= k = \ r -> k (f r) r
From the definitions it's able to see that they actually behave the same exactly.
So are they interchangeable in all usages? And what's the actual significance of differing these two Monads?
They are the same.
State
, Writer
and Reader
were inspired by Mark P. Jones' Functional Programming with Overloading and
Higher-Order Polymorphism, where he defined Reader
as follows:
A
Reader
monad is used to allow a computation to access the values held in some enclosing environment (represented by the typer
in the following definitions).> instance Monad (r->) where > result x = \r -> x > x `bind` f = \r -> f (x r) r
As a passing comment, it is interesting to note that these two functions are just the standard
K
andS
combinators of combinatory logic.
Later, he defines (almost) today's MonadReader
:
Reader monads
: A class of monads for describing computations that consult some fixed environment:> class Monad m => ReaderMonad m r where > env :: r -> m a -> m a > getenv :: m r > instance ReaderMonad (r->) r where > env e c = \_ -> c e > getenv = id
getenv
is simply ask
, and env
is local . const
. Therefore, this definition already contained all significant parts of a Reader
. Ultimately, Jones defines the monad transformer ReaderT
(BComp
is backward composition):
To begin with, it is useful to define two different forms of composition; forwards (
FComp
) and backwards (BComp
):> data FComp m n a = FC (n (m a)) > data BComp m n a = BC (m (n a))
[omitting Functor, Monad and OutOf instances]
> type ReaderT r = BComp (r ->)
Since StateT
, WriterT
, and others had their non-transformer variant, it was only logical to have a Reader r
, which really is the same as (->) r
.
Either way, nowadays Reader
, Writer
and State
are defined in terms of their transformer variant, and you use their respective Monad*
typeclass (MonadReader
).
So are they interchangeable in all usages?
Yes.
And what's the actual significance of differing these two Monads?
None, except that ReaderT
is actually a monad transformer, which makes things easier.
They are both instance of the MonadReader
class. So yes, you can use one instead of the other.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With