Skip to content

Commit 334c4b4

Browse files
author
Arnaud ESTEVE
committed
attempt at explaining the reader monad
1 parent 66ebcfb commit 334c4b4

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

docs/docs/reference/contextual/typeclasses-new.md

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,58 @@ given optionMonad as Monad[Option] {
201201
Another example of a `Monad` is the Reader Monad. It no longer acts on a type like `List` or `Option`, but on a function.
202202
It can be used for example for combining functions that all need the same type of parameter. For instance multiple functions needing access to some configuration, context, environment variables, etc.
203203

204-
The Reader monad allows to abstract over such a configuration dependency (or context, environment, ...), named `Ctx` in the following examples. It is therefore _parameterized_ by `Ctx`:
204+
Let us have a `Config` type, and two functions using it:
205+
206+
```scala
207+
trait Config
208+
def compute(i: Int)(config: Config): String = ???
209+
def show(str: String)(config: Config): Unit = ???
210+
```
211+
212+
We may want to combine `compute` and `show` into a single function, accepting a `Config` as parameter, and showing the result of the computation.
213+
If we had a `flatMap` function as in the examples above, we would be able to write the following:
214+
215+
```scala
216+
def computeAndShow(i: Int): Config => Unit = compute(i).flatMap(show)
217+
```
218+
219+
Let's define this `Monad` then. First, we are going to define a type named `ConfigDependent` representing a function that when passed a `Config` produces a `Result`.
220+
221+
```scala
222+
trait Config // the Config defined above
223+
type ConfigDependent[Result] = Config => Result
224+
```
225+
226+
The monad will look like this:
227+
228+
```scala
229+
given configDependentMonad as Monad[ConfigDependent]
230+
def [A, B](r: ConfigDependent[A]).flatMap(f: A => ConfigDependent[B]): ConfigDependent[B] =
231+
config => f(r(config))(config)
232+
def pure[A](x: A): ConfigDependent[A] =
233+
config => x
234+
```
235+
236+
The type `ConfigDependent` can be written using [type lambdas](../new-types/type-lambdas.html):
237+
238+
```scala
239+
type ConfigDependent = [Result] =>> Config => Result
240+
```
241+
242+
Using this syntax would turn the previous `configReaderMonad` into:
243+
244+
245+
```scala
246+
given configDependentMonad as Monad[[Result] =>> Config => Result]
247+
def [A, B](r: Config => A).flatMap(f: A => Config => B): Config => B =
248+
config => f(r(config))(config)
249+
def pure[A](x: A): Config => A =
250+
config => x
251+
```
252+
253+
254+
255+
The Reader monad allows to abstract over the `Config` type, named `Ctx` in the following examples. It is therefore _parameterized_ by `Ctx`:
205256

206257
```scala
207258
given readerMonad[Ctx] as Monad[[X] =>> Ctx => X] {

0 commit comments

Comments
 (0)