Bonus: The M Word (Scala 3 Video)
Were you expecting to see monads in this book? If so, you won’t be disappointed. :)
Almost all of the data types I showed in this book are monads. This includes Option
, Try
, Either
, List
, Seq
, Vector
, IO
, and ZIO
: they’re all monads, or what we call monadic data types.
I won’t get into mathematical theory here, but in Scala, a monad is primarily a data type that properly implements map
and flatMap
methods so that it can be used in for
expressions. There’s a little more to it than that, but from an implementation standpoint, that’s the big thing. As I’ve shown, you can use flatMap
to run a few effects in sequence, and for
expressions to run many effects in sequence.
And as I show in Functional Programming, Simplified,
for
expressions are syntactic sugar that compile down to a series offlatMap
calls followed by a singlemap
call.
Sequential composition
The key about monads in any language is that they allow you to guarantee that effects will occur in order (i.e., sequentially). For example, Haskell is a lazy (or lazily evaluated) programming language, and part of what that means is that whenever the Haskell compiler sees that it can run expressions in parallel, it might just do that.
However, when you prompt a user for input, like this:
print("Your input: ")
you really want to make sure that your “prompt the user” code occurs before your “read their input” code:
val input = readInput()
To make any sense, those operations must occur in that order, one after the other. In Haskell, you use its do
construct to ensure that expressions are run in sequence, and in Scala you similarly sequence them in for
expressions, like this:
for
_ <- promptUser()
input = readInput()
// more code here ...
If you recall that the ZIO
type is a “blueprint for describing a concurrent workflow,” you should think, “If promptUser
and readInput
run concurrently, I need to use a for
expression or flatMap
to make sure those two functions are called in the proper order.”
For this reason, some people refer to monads as the “semi-colon in FP.” They let us run our effects in a guaranteed sequence, so even if our functions are meant to run in parallel, flatMap
and for
expressions guarantee that they’re run in sequence, just like procedural code.
Monads in Scala
But again, the key in Scala is that these monadic data types properly implement the map
and flatMap
methods inside their classes, and this is what enables them to be used in for
expressions. I write about this in great detail in these two resources:
- My blog post, How to Write a Scala Class That Can Be Used in a for-Expression
- My best-selling FP book, Functional Programming, Simplified
Category Theory
For those who are interested in the theory behind names like monad, monoid, functor, and other FP terms with unusual names, the next thing you’ll want to dig into is category theory (which is where the name “Cats Effect” comes from).
You can find a free version of a book named Category Theory for Programmers at these locations:
As I’ve shown in this book, you don’t need to understand category theory to understand FP, but when you want to know where names like “map” come from, category theory is what you’re looking for.
Update: All of my new videos are now on
LearnScala.dev