Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between Monad.Reader and the (->) monads?

Tags:

haskell

monads

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?

like image 730
Shou Ya Avatar asked Mar 05 '15 08:03

Shou Ya


2 Answers

TL;DR

They are the same.

Some history lessons

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 type r 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 and S 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).

Conclusion

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.

like image 198
Zeta Avatar answered Oct 06 '22 11:10

Zeta


They are both instance of the MonadReader class. So yes, you can use one instead of the other.

like image 24
Nicolas Avatar answered Oct 06 '22 13:10

Nicolas