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

I found out that Monad.Reader is actually an encapsulation of a function, namely:

newtype Reader ra = Reader { runReader :: r -> a } 

What is done by the Monad instance,

 instance Monad (Reader r) where return a = Reader $ \_ -> a m >>= k = Reader $ \r -> runReader (k (runReader mr)) r 

In contrast, I knew that (->) is also a monad,

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

From the definitions he can see that they really behave the same exactly.

So are they interchangeable in all customs? And what is the real significance of the differences between the two Monads?

+6
source share
3 answers

TL DR

They are the same.

Some history lessons

State , Writer and Reader were inspired by Marx Jones Functional Programming with Overload and Higher Order Polymorphism , where he defined Reader as follows:

A Reader monad is used to allow a calculation to access stored values ​​in some environment (represented by type r in the following definition).

 > instance Monad (r->) where > result x = \r -> x > x `bind` f = \r -> f (xr) r 

As a missing comment, it is interesting to note that these two functions are simply standard K and S combinatorial combinators.

He later defines (almost) today MonadReader :

Reader monads : a monad class for describing computations that are considered in some fixed environment:

 > class Monad m => ReaderMonad mr where > env :: r -> ma -> ma > getenv :: mr > instance ReaderMonad (r->) r where > env ec = \_ -> ce > getenv = id 

getenv just ask , and env is local . const local . const . Therefore, this definition already contained all the relevant parts of a Reader . Ultimately, Jones defines the ReaderT monad ReaderT ( BComp is the reverse composition):

To begin with, it is useful to define two different forms of composition; forward ( FComp ) and backward ( BComp ):

 > data FComp mna = FC (n (ma)) > data BComp mna = BC (m (na)) 

[excluding instances of Functor, Monad and OutOf]

 > type ReaderT r = BComp (r ->) 

Since StateT , WriterT , and others have their own version without a transformer, it would be logical to have Reader r , which is actually the same as (->) r .

In any case, Reader , Writer and State are currently defined in terms of their version of the transformer, and you use their corresponding Monad* typeclass ( MonadReader ).

Conclusion

So are they interchangeable in all customs?

Yes.

And what is the real significance of the differences between the two Monads?

No, except that ReaderT is actually a monad transformer, which simplifies the work.

+9
source

They are both instances of the MonadReader class. So yes, you can use one and not the other.

+1
source

They are actually the same. We can do this more formal by matching between them: toArrow :: Reader ra -> r -> a and toReader :: (r -> a) -> Reader ra with implementations toReader = Reader and toArrow = runReader .

Edit: The semantics behind Reader are that it contains some read-only configuration that you can thread through a chain of calculations. You should always use Reader , using the simple arrow type, when you want to insert some configuration information, as it is part of a very universal interface that provides useful helper functions, the MonadReader class for managing Reader similar type data, and ReaderT for stacking Monad s.

0
source

Source: https://habr.com/ru/post/983359/


All Articles