What exactly do you use Reader<T> for?
See original GitHub issueI’ve been going through some of the old issues, as there are some gems hidden away there. Along the way, I’ve seen a couple of answers by @louthy where he’s used the Reader<T>
monad, apparently to carry state/environment around. See this one and this one for examples.
However, I can’t get a clear picture of exactly what this monad gives us, and how we use it.
Can anyone give me a simple explanation, preferably with code, showing a situation in which Reader<T>
provides a specific benefit. This would be really useful.
Thanks in advance.
Issue Analytics
- State:
- Created 5 years ago
- Comments:13 (13 by maintainers)
Top Results From Across the Web
The ReaderT Design Pattern
This data type will contain all runtime configuration and global functions that may be mockable (like logging functions or database access). If ...
Read more >What is the purpose of * in the ReaderT Monad Transformer?
* is the kind of types with values : it stands for things like Int , List Int etc.. forall k means k...
Read more >Who still uses ReaderT
Who still uses ReaderT. Monad transformers are a pretty amazing skill in any haskellers tool set, and can be a pleasure to work...
Read more >What is MonadReader for when we have ReaderT? ...
The ReaderT is a newtype , and you can use it to pass a value around your monads such that it can be...
Read more >Ep 12: ReaderT is good for the environment - YouTube
I implemented and used the WriterT monad a couple of videos ago, ... some data through our program, and instead use the ReaderT...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
The Reader Monad is commonly used to thread configuration through application code to call sites that depend on it. It offers a form of dependency injection.
Imagine you have a
UserRepository
used by a number of methods. In typical c# code, you either need to pass theUserRepository
to each method or use an IoC container to inject the dependency wherever it’s needed.The reader monad allows you to compose methods that require a
UserRepository
(or any dependency) without explicitly passing this dependency around.For example
Notice that
GetUserById
andGetUserByName
useUserRepository
byask'ing
for it but without having to have it explicitly passed to them. Also noteGetUserAandBoss
is able to compose methods returning readers. Notice also thatReader
has two generic typesEnv
andA
.Env
is always fixed (in our case asUserRepository
), but the type ofA
can change, theA
inGetUserAandBoss
isstring
but theA
inGetUserByName
andGetUserById
isUser
.To actually execute, you need to call
run
passing in the dependency that will now be threaded throughout the composed chain and then matching on the result.So to sum up,
Reader
is typically used for dependency injection (as shown in https://github.com/louthy/language-ext/issues/515) or configuration. You have aConfiguration
object with a bunch a settings that the methods throughout your code base need to access, but you don’t want to have to explicitly passConfiguration
throughout your application. Instead you have aReader<Configuration, A>
and then at the entry point of you application, you load yourConfiguration
from somewhere and callRun
.Having said also this, I’m new to all this myself and am happy to be corrected.
I really like this comment.
I have noticed that an expression with (say) two dependencies can either be the entire body of a function that requires both dependencies or part of the curried version of that function, which effectively moves a type from being part of the input to being part of the output.
For example,
C Function(A a, B b)
curries toFunc<B, C> CurriedFunction(A a)
and the typeB
has “moved” from the being part o the input (A
andB
) to being part of the output (Func<B, C>
).Since you have to “see”
B
either on the right as part of the input or on the left as part of the output, I don’t see an advantage one way or the other from a syntactic perspective.What does seem different those is a separation of “what to do” and “when to do it” regarding
B
.If your signature is
C Function(A a, B b)
, then when it finishes executing,A
andB
have (presumably) been used andC
has been computed. In particular, any side effects involved with accessingB
have occurred.On the other had, if your signature is
Func<B, C> CurriedFunction(A a)
, then when it finishes executing, how to useB
has been specified, butB
hasn’t been used yet, so any side effects involved with accessingB
have not occurred.This seems like the real advantage to me.
The example I gave above comparing a function and its curried form is how I first became aware of this situation. However, a curried function is certainly just a special case of separating “what to do” and “when to do it”. My impression is that the “purpose” of the reader monad could be to preciously express the separation “what to do” and “when to do it” in the case of reading (as opposed to the case of writing, which is handled by the writer monad).