Skip to content

Commit 4148284

Browse files
feat: better monadic hints in assign6 handout
1 parent d6f9977 commit 4148284

File tree

1 file changed

+61
-5
lines changed

1 file changed

+61
-5
lines changed

assign6/README.md

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,73 @@ Should produce:
9494
Course not found.
9595
```
9696
97-
### Hints:
98-
There are three monadic operations `and_then`, `transform`, and `or_else`. Read the description of each of them in the lecture slides, and take a look at [here](https://en.cppreference.com/w/cpp/utility/optional). Namely, you only need 2 of the mondadic operations.
97+
### Monadic Operations
98+
99+
There are three monadic operations: [`and_then`](https://en.cppreference.com/w/cpp/utility/optional/and_then), [`transform`](https://en.cppreference.com/w/cpp/utility/optional/transform), and [`or_else`](https://en.cppreference.com/w/cpp/utility/optional/or_else). Read the description of each of them in the lecture slides, and take a look at [the standard library documentation](https://en.cppreference.com/w/cpp/utility/optional). You will only need to use 2 of the mondadic operations.
99100
100101
Your code should end up looking something like this:
101102
102103
```cpp
103-
std::string output = course.<MONADIC_FN1>(<SOME LAMBDA FN>)
104-
.<MONADIC_FN2>(...);
104+
std::string output = course
105+
./* monadic function one */ (/* ... */)
106+
./* monadic function two */ (/* ... */)
107+
.value(); // OR `.value_or(...)`, see below
105108
```
106109
107-
Notice the lambda function being passed into the first monadic function. This should be a hint! **Think about what type output is** and what you're monadic opertaions therefore need to return/produce.
110+
It can help to **think about what the type of `output` is and work backwards from there**. Pay attention to what each of the monadic functions does, as described in the hint below.
111+
112+
> [!NOTE]
113+
> Recall what the role is of each of the monadic functions. The official C++ library doesn't do a good job explaining this, so we have included a short reference here. Suppose `T` and `U` are arbitrary types.
114+
>
115+
> ```cpp
116+
> /**
117+
> * tl;dr;
118+
> * Calls a function to produce a new optional if there is a value; otherwise, returns nothing.
119+
> *
120+
> * The function passed to `and_then` takes a non-optional instance of type `T` and returns a `std::optional<U>`.
121+
> * If the optional has a value, `and_then` applies the function to its value and returns the result.
122+
> * If the optional doesn't have a value (i.e. it is `std::nullopt`), it returns `std::nullopt`.
123+
> */
124+
> template <typename U>
125+
> std::optional<U> std::optional<T>::and_then(std::function<std::optional<U>(T)> func);
126+
>
127+
> /**
128+
> * tl;dr;
129+
> * Applies a function to the stored value if present, wrapping the result in an optional, or returns nothing otherwise.
130+
> *
131+
> * The function passed to `transform` takes a non-optional instance of type `T` and returns a non-optional instance of type `U`.
132+
> * If the optional has a value, `transform` applies the function to its value and returns the result wrapped in an `std::optional<U>`.
133+
> * If the optional doesn't have a value (i.e. it is `std::nullopt`), it returns `std::nullopt`.
134+
> */
135+
> template <typename U>
136+
> std::optional<U> std::optional<T>::transform(std::function<U(T)> func);
137+
>
138+
> /**
139+
> * tl;dr;
140+
> * Returns the optional itself if it has a value; otherwise, it calls a function to produce a new optional.
141+
> *
142+
> * The opposite of `and_then`.
143+
> * The function passed to `or_else` takes a non-optional instance of type `T` and returns a `std::optional<U>`.
144+
> * If the optional has a value, `or_else` returns it.
145+
> * If the optional doesn't have a value (i.e. it is `std::nullopt`), `or_else applies the function to its value and returns the result.
146+
> */
147+
> template <typename U>
148+
> std::optional<U> std::optional<T>::or_else(std::function<std::optional<U>(T)> func);
149+
> ```
150+
>
151+
> For example, given a `std::optional<T> opt` object, the monadic operations could be invoked as follows:
152+
>
153+
> ```cpp
154+
> opt
155+
> .and_then([](T value) -> std::optional<U> { return /* ... */; })
156+
> .transform([](T value) -> U { return /* ... */; });
157+
> .or_else([](T value) -> std::optional<U> { return /* ... */; })
158+
> ```
159+
>
160+
> <sup>Note that the `->` notation in the lambda function is a way of explicitly writing out the return type of the function!</sup>
161+
>
162+
> Notice that since each method returns an `std::optional`, you can chain them together. If you are certain that the optional will have a value at the end of the chain, you could call [`.value()`](https://en.cppreference.com/w/cpp/utility/optional/value) to get the value. Otherwise, you could call [`.value_or(fallback)`](https://en.cppreference.com/w/cpp/utility/optional/value_or) to get the result or some other `fallback` value if the optional doesn't have a value.
163+
108164
109165
110166
## 🚀 Submission Instructions

0 commit comments

Comments
 (0)