Skip to content

Commit b8d288c

Browse files
committed
Start on Monads chapter
1 parent 750d617 commit b8d288c

File tree

2 files changed

+46
-39
lines changed

2 files changed

+46
-39
lines changed

src/pages/monads/cats.typ

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,48 +37,58 @@ val list3 = Monad[List].map(list2)(a => a + 123)
3737

3838
`Monad` provides many other methods,
3939
including all of the methods from `Functor`.
40-
See the #href("http://typelevel.org/cats/api/cats/Monad.html")[scaladoc] for more information.
40+
See the #href("http://typelevel.org/cats/api/cats/Monad.html")[documentation] for more information.
41+
4142

42-
=== Default Instances
4343

44+
=== Default Instances
4445

4546
Cats provides instances for all the monads in the standard library
4647
(`Option`, `List`, `Vector` and so on).
4748
Cats also provides a `Monad` for `Future`.
4849
Unlike the methods on the `Future` class itself,
4950
the `pure` and `flatMap` methods on the monad
50-
can't accept implicit `ExecutionContext` parameters
51+
can't accept `ExecutionContext` parameters
5152
(because the parameters aren't part of the definitions in the `Monad` trait).
5253
To work around this, Cats requires us to have an `ExecutionContext` in scope
53-
when we summon a `Monad` for `Future`:
54+
when we summon a `Monad` for `Future`.
55+
56+
Let's import `Future` (and some other imports we will use later.)
5457

5558
```scala mdoc:silent
5659
import scala.concurrent.*
5760
import scala.concurrent.duration.*
5861
```
5962

63+
We see that compilation fails without an `ExecutionContext` available.
64+
6065
```scala mdoc:fail
66+
6167
val fm = Monad[Future]
6268
```
6369

64-
Bringing the `ExecutionContext` into scope
65-
fixes the implicit resolution required to summon the instance:
70+
Now we bring the `ExecutionContext` into scope.
6671

6772
```scala mdoc:silent
6873
import scala.concurrent.ExecutionContext.Implicits.global
6974
```
7075

76+
This provides the given instance required to summon the `Monad[Future]` instance:
77+
7178
```scala mdoc
7279
val fm = Monad[Future]
7380
```
7481

7582
The `Monad` instance uses the captured `ExecutionContext`
76-
for subsequent calls to `pure` and `flatMap`:
83+
for subsequent calls to `pure` and `flatMap`.
84+
We can construct a `Future` using calls to the monad instance we summoned above.
7785

7886
```scala mdoc:silent
7987
val future = fm.flatMap(fm.pure(1))(x => fm.pure(x + 2))
8088
```
8189

90+
If we await the result of the `Future` we get the expected result.
91+
8292
```scala mdoc
8393
Await.result(future, 1.second)
8494
```
@@ -87,8 +97,8 @@ In addition to the above,
8797
Cats provides a host of new monads that we don't have in the standard library.
8898
We'll familiarise ourselves with some of these in a moment.
8999

90-
=== Monad Syntax
91100

101+
=== Monad Syntax
92102

93103
The syntax for monads comes from three places:
94104

@@ -100,7 +110,7 @@ The syntax for monads comes from three places:
100110
provides syntax for `pure`.
101111

102112
In practice it's often easier to import everything in one go
103-
from `cats.syntax.all.**`.
113+
from `cats.syntax.all.*`.
104114
However, we'll use the individual imports here for clarity.
105115

106116
We can use `pure` to construct instances of a monad.

src/pages/monads/index.typ

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
#chapter[Monads] <sec:monads>
33

44

5-
*Monads* are one of the most common abstractions in Scala.
6-
Many Scala programmers quickly become intuitively familiar with monads,
5+
*Monads* are one of the best known abstractions in functional programming,
6+
but also the one that perhaps leads to the most confusion.
7+
Many programmers have used and are intuitively familiar with monads,
78
even if we don't know them by name.
89

9-
Informally, a monad is anything with a constructor and a `flatMap` method.
10+
A monad in Scala is, informally, anything with a constructor and a `flatMap` method.
1011
All of the functors we saw in the last chapter are also monads,
1112
including `Option`, `List`, and `Future`.
1213
We even have special syntax to support monads: for comprehensions.
@@ -23,17 +24,15 @@ Finally, we'll tour some interesting monads that you may not have seen,
2324
providing introductions and examples of their use.
2425

2526

26-
== What is a Monad?
2727

28+
== What is a Monad?
2829

2930
This is the question that has been posed in a thousand blog posts,
3031
with explanations and analogies involving concepts as diverse as
3132
cats, Mexican food, space suits full of toxic waste,
3233
and monoids in the category of endofunctors (whatever that means).
3334
We're going to solve the problem of explaining monads once and for all
34-
by stating very simply:
35-
36-
> A monad is a mechanism for _sequencing computations_.
35+
by stating very simply: a monad is a mechanism for _sequencing computations_.
3736

3837
That was easy! Problem solved, right?
3938
But then again, last chapter we said functors
@@ -45,7 +44,7 @@ we said that functors allow us
4544
to sequence computations ignoring some complication.
4645
However, functors are limited in that
4746
they only allow this complication
48-
to occur once at the beginning of the sequence.
47+
to occur once, at the beginning of the sequence.
4948
They don't account for further complications
5049
at each step in the sequence.
5150

@@ -61,8 +60,8 @@ allowing us to `flatMap` again.
6160
Let's ground things by looking at some examples.
6261

6362

64-
=== Options as Monads
6563

64+
=== Options as Monads
6665

6766
`Option` allows us to sequence computations
6867
that may or may not return values.
@@ -121,7 +120,7 @@ stringDivideBy("bar", "2")
121120
Every monad is also a functor (see below for proof),
122121
so we can rely on both `flatMap` and `map`
123122
to sequence computations
124-
that do and don't introduce a new monad.
123+
that do and don't introduce a new monad respectively.
125124
Plus, if we have both `flatMap` and `map`
126125
we can use for comprehensions
127126
to clarify the sequencing behaviour:
@@ -143,8 +142,8 @@ def stringDivideBy(aStr: String, bStr: String): Option[Int] =
143142
```
144143

145144

146-
=== Lists as Monads
147145

146+
=== Lists as Monads
148147

149148
When we first encounter `flatMap` as budding Scala developers,
150149
we tend to think of it as a pattern for iterating over `Lists`.
@@ -174,23 +173,22 @@ which states the sequence of operations:
174173
- get `y`
175174
- create a tuple `(x, y)`
176175

177-
<!--
178176
The type chart in @fig:monads:list-type-chart
179-
illustrates this behaviour[^list-lengths].
177+
illustrates this behaviour#footnote[
178+
Although the result of `flatMap` (`List[B]`)
179+
is the same type as the result of the user-supplied function,
180+
the end result is actually a larger list
181+
created from combinations of intermediate `As` and `Bs`.
182+
].
180183

181184
#figure(
182185
image("list-flatmap.svg", width: 80%),
183186
caption: [Type chart: flatMap for List]
184187
)<fig:monads:list-type-chart>
185188

186-
[^list-lengths]: Although the result of `flatMap` (`List[B]`)
187-
is the same type as the result of the user-supplied function,
188-
the end result is actually a larger list
189-
created from combinations of intermediate `As` and `Bs`.
190-
-->
191189

192-
=== Futures as Monads
193190

191+
=== Futures as Monads
194192

195193
`Future` is a monad that sequences computations
196194
without worrying that they may be asynchronous:
@@ -252,27 +250,29 @@ but that is another story and shall be told another time.
252250
Monads are all about sequencing.
253251

254252

255-
=== Definition of a Monad
256253

254+
=== Definition of a Monad
257255

258256
While we have only talked about `flatMap` above,
259257
monadic behaviour is formally captured in two operations:
260258

261259
- `pure`, of type `A => F[A]`;
262-
- `flatMap`[^bind], of type `(F[A], A => F[B]) => F[B]`.
263-
264-
[^bind]: In the programming literature and Haskell,
265-
`pure` is referred to as `point` or `return` and
266-
`flatMap` is referred to as `bind` or `>>=`.
260+
- `flatMap`#footnote[
261+
In the programming literature and Haskell,
262+
`pure` is often referred to as `point` or `return` and
263+
`flatMap` is often referred to as `bind` or `>>=`.
267264
This is purely a difference in terminology.
268265
We'll use the term `flatMap` for compatibility
269266
with Cats and the Scala standard library.
267+
], of type `(F[A], A => F[B]) => F[B]`.
270268

271269
`pure` abstracts over constructors,
272270
providing a way to create a new monadic context from a plain value.
273271
`flatMap` provides the sequencing step we have already discussed,
274272
extracting the value from a context and generating
275273
the next context in the sequence.
274+
275+
We can represent this as a type class.
276276
Here is a simplified version of the `Monad` type class in Cats:
277277

278278
```scala mdoc:silent
@@ -284,10 +284,7 @@ trait Monad[F[_]] {
284284
}
285285
```
286286

287-
#warning[
288-
==== Monad Laws {-}
289-
290-
287+
#info(title: "Monad Laws")[
291288
`pure` and `flatMap` must obey a set of laws
292289
that allow us to sequence operations freely
293290
without unintended glitches and side-effects:
@@ -319,7 +316,7 @@ m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g))
319316

320317

321318
Every monad is also a functor.
322-
We can define `map` in the same way for every monad
319+
For every monad we can define `map` in the same way
323320
using the existing methods, `flatMap` and `pure`:
324321

325322
```scala mdoc:silent:reset-object

0 commit comments

Comments
 (0)