<
### Learn about the Reader Monad

## Monads are functional design patterns

### They solve a large range of problems that come out in functional programming

## Composition with side effects requires a common interface

## For Monads this means two higher order functions: pure and bind

## Let's relate this to something you might know: range-v3

## Pure lifts values into other domains

## Transforming and joining is the task for bind

## Bind in range-v3 is called views::for_each

### These are the higher order functions that we will need today

## Monads are also Functors and Applicatives

## The particularity of a Monad is that it allows for a choice, i.e. different paths in a computation

## The Reader Monad propagates shared environment untouched along the computational chain

## The environment is often a database, a repository or a configuration

## The environment is not readily available and will be injected later

## The Reader Monad removes an explicit use of the dependency from the computational chain's API

### The dependency is moved from the input arguments into the return type

### In principle the Reader is a function

## Let's look at a concrete example

## A shop will run an offer for a bundle of ingredients to make Caprese

### The prices of ingredients will be retrieved

from a database

The database:

### We will perform operations on the data retrieved from the yet unavailable database

### We wish to remove any explicit mention of the database dependency from the call chain

### Since the database isn't available, the Reader must be curried

### Replacing m with _ clarifies that we are missing the database

### Prices independent from the database follow the same structure but ignore the environment.

## read_price and just_price instances are the subjects of our transformations

## They can be constructed using fmap, ask and a selector function.

We skip this.

## Think of monads as transformations. Don't dwell too much on monad constructors.

## Remember that read_price('t') doesn't return a value, it'a function
of the environment.

### We obtain the actual value much later once we inject the database

### Our Caprese example demonstrates

three facets of the Reader

## Functor: Let's apply discount to the tomato

## We will get the tomato price from the database that isn't available.
The input is the 'stub' reader read_price('t')

## Discount is a pure function

(double → double)

### This is the task for fmap

### The actual values are produced only once we inject the database

### fmap executes the action ra in the environment e and constructs a new action rb

### ra(e) gives us a value (price etc.) after we inject the database

## Applicative:

Let's add prices of two items together

## This is the job of pure & apply

## Addition is a binary function but apply takes a unary function.

How do we deal with this?

### We provide a curried add function that can take one argument at a time

### We lift the curried add function

into the Reader world

### We use apply in a nested fashion

### Things get out of hand pretty fast

### Now with better curry

### pure lifts a value into the Reader world

## How come we did not lift the discount function in case of fmap?

## This is because fmap did it for us

### apply constructs a follow-up action by running both the lifted function and ra
in the environment

### The position of apply determines

what rf(e)(ra(e)) represents

## Applicatives let us chain operations

## But only monads allow us to select the next computation based on the result of the previous computation

## Monad: Let's choose the next item based on the price of the previous item

## The monadic aspect is implemented using pure (return) & bind

## fmap and apply

can be expressed in terms of

pure and bind

## But this approach might introduce some unnecessary sequencing

## Let's pick a cheaper tomato if the basil & mozzarella are too expensive

### The function that picks tomatoes is

a world-crossing function

### bind ties a world-crossing function to a monad

### We had to pick the cheaper tomato

### Due to the presence of the Reader in the world-crossing function bind constructs an intermediate action

### bind constructs an intermediate action

### Finally, here are the most important takeaways

- absence of a meaningful result -
**std::optional** - asynchronous operations -
**std::future** - propagation of shared environment -
**Reader monad** - logging mechanism -
**Writer monad** - state mutations -
**State monad** - dealing with input and output -
**IO monad**

Applicative **views::single**, as well as monadic **yield** are world-crossing operations. They lift a value into a range.

**views::for_each** is the most unfortunate name for a transform / flatten operation.

You can think of range-v3 for reference.

fmap | views::transform |

pure | views::single, yield |

apply* | views::zip_with |

bind | views::for_each |

We often need to use functor and applicative aspects rather than the monadic aspect

The return type is a now a function <A(E)>.

This is how Reader compares to std::vector for fmap:

- A,B....types
- E.......the fixed environment to be propagated (the database)

from a database

- represents the dependency that will be injected later
- will be emulated by std::map<char,double>

tomato | 2.4 |

mozzarella | 2.7 |

basil | 3.2 |

- retrieve prices of items from the database
- apply discount to some of the items
- find out the total value of the basket
- pick items based on the price of other items

Remember that we are not allowed to hold any state.

We can deliver the key but not the map.

This is a common starting point for monadic transformations.

The independent price is being lifted into the Reader environment.

We skip this.

This is somewhat like stubbing in testing.

three facets of the Reader

- Functor's fmap - applying discount
- Applicative's pure & apply - adding prices of items
- Monad's bind - choosing the next item based on the previous item

(double → double)

- fmap takes the discount function
**(double → double)** - and the tomato reader with the database dependency
- and creates a new reader that carries the dependency and knows how to apply the discount

- f....the discount function
- ra...read_price('t')
- e....environment (database)

This happens when we use the call operator of the composed lambda.

Let's add prices of two items together

How do we deal with this?

into the Reader world

a...in our case the curried add function

what rf(e)(ra(e)) represents

position | ra(e) | rf(e) (ra(e)) | eventually |

outer apply | 0.5 | f1 (0.5) | -0.5 |

middle apply | 2.7 | f2 (2.7) (?) | 0.9*2.7 - 0.5 |

inner apply | 2.4 | f3 (2.4) (?) (?) | 2.4 + 0.9*2.7 - 0.5 |

can be expressed in terms of

pure and bind

a world-crossing function

**Hint**: Returning **std::optional<int>** when parsing a string is also a world-crossing function.

**pick_tomato**expects a boolean but**read_1**is a monad- also, based on the bool we need to construct
**read_price('x')**or**read_price('t')**

ra(e) | determine if price was exceeded... true / false |

f(ra(e)) | based on the result construct read_price('x') or read_price('t') |

f(ra(e))(e) | execute read_price('x') or read_price('t') |

- Reader propagates shared environment.
- Reader does away with global context and dependency function arguments.
- It's a function or action to be executed.
- Common uses require its functor and applicative aspect.
- Monadic aspect is useful for picking items based on previous items.