When you get started with functional programming (FP) a common question you’ll have is, “What is an effect in functional programming?” You’ll hear advanced FPers use the words *effects* and *effectful*, but it can be hard to find a definition of what these terms mean.

## Effects are related to monads

The first step in the process of understanding effects is to say that they’re related to monads, so you have to know a little bit about monads to understand effects.

As I wrote in my book, Functional Programming, Simplified, a slight simplification is to say that a *monad* is any class that implements the `map`

and `flatMap`

methods. Because of the way Scala for-expressions work, implementing those two methods lets instances of that class be chained together in for-expressions (for/yield expressions).

That leads to the benefit of monads in Scala: they let you sequence a series of operations together. For example, if every function returns an `Option`

, you can sequence the functions together in a for-expression:

```
def fInt(): Some[Int] = Some(1)
def fDouble(): Some[Double] = Some(1.0)
def fString(): Some[String] = Some("joe")
val x = for {
a <- fInt()
b <- fDouble()
c <- fString()
} yield (a,b,c)
// x: Option[(Int, Double, String)] = Some((1,1.0,joe))
```

Indeed, when people use the term *monadic* in Scala you can typically replace the word “monadic” with “in a for-expression.”

Back to topSummary: Step 1 is knowing that a monad in Scala is simply a class that implements

`map`

and`flatMap`

so it can be used in a for-expression. (That’s a slight over-simplification, but good enough for now.)

## Not a side effect, but the main effect

Now that we know that we’re talking about monads, the next important part is to understand the meaning of the word “effect.” A good way to describe this is to say that we’re *not* talking about a *side effect* — we’re talking about *a main effect*, i.e, the main purpose of each individual monad. An effect is what the monad does.

This first became clear when I read the book, Functional and Reactive Domain Modeling, and came across these statements:

`Option`

models the effect of optionality`Future`

models latency as an effect`Try`

abstracts the effect of failures (manages exceptions as effects)

Those statements can also be written like this:

`Option`

*is a monad*that models the effect of optionality`Future`

*is a monad*that models latency as an effect`Try`

*is a monad*that abstracts the effect of failures (manages exceptions as effects)

Similarly:

`Reader`

is a monad that abstracts the effect of composing operations that depend on some input`Writer`

is a monad that models logging as an effect`State`

is a monad that abstracts the effect of state (composing a series of computations that maintain state)

So again, an effect is the thing a monad does. In terms of code, it’s how a monad implements its `flatMap`

method to achieve that effect.

Back to topNote: In Haskell, the equivalent of the

`flatMap`

method is known as`bind`

.

## Effectful functions return F[A] rather than [A]

In a YouTube video titled, Functional Programming with Effects, Rob Norris makes an interesting point: he says that an *effectful* function is a function that returns `F[A]`

rather than `[A]`

. For example, this function returns `Option[Int]`

rather than `Int`

:

```
def toInt(s: String): Option[Int] = {
try {
Some(Integer.parseInt(s.trim))
} catch {
case e: Exception => None
}
}
```

In creating `toInt`

you *could* write a function that returns `Int`

, but the only ways to do that are:

- Return
`0`

if the conversion fails, or - Return
`null`

if the conversion fails

Regarding the first case, this is a bad idea because users will never know if the function received `"0"`

or something like `"fred"`

that won’t convert to a number. Regarding the second case, using `null`

is a bad practice in both OOP and FP, so that approach is just a bad idea.

Therefore, the only logical thing to do is to return an instance of `Option`

, i.e., a `Some[Int]`

or a `None`

. This is what Mr. Norris means when he says that an effectful function returns `F[A]`

rather than `[A]`

. In the `toInt`

example:

`F[A]`

is`Option[Int]`

`A`

is the raw`Int`

type

Now, because `toInt`

is effectful — meaning that it returns an `F[A]`

, which is a monadic type — it can be used in for-expressions like this:

```
val x = for {
a <- toInt(string1)
b <- toInt(string2)
c <- toInt(string3)
} yield (a + b + c)
```

The result of this expression is that `x`

will be a `Some[Int]`

or a `None`

.

I don’t remember where I read it, but someone said that if you want to think about it philosophically, when a function returns an `A`

, that `A`

has already been *fully evaluated*; but if that function returns `F[A]`

instead, that result *has not* already been fully evaluated. So, rather than writing a function that returns a raw type, an effectful function returns a raw type inside a useful wrapper — where that wrapper is a monad that lets the result be used in a monadic style (i.e., in a Scala for-expression).

## Summary

For some reason my brain has a hard time absorbing the words *effect* and *effectful* when people talk about things abstractly, so I decided to dig into this topic and then share my notes here.

As mentioned, rather than thinking of a *side effect*, an effect is the *main effect* of a monad that you’re using:

`Option`

*is a monad*that models the effect of optionality`Future`

*is a monad*that models latency as an effect`Try`

*is a monad*that abstracts the effect of failures (manages exceptions as effects)`Reader`

is a monad that abstracts the effect of composing operations that depend on some input`Writer`

is a monad that models logging as an effect`State`

is a monad that abstracts the effect of state (composing a series of computations that maintain state)

Furthermore, when a function is said to be *effectful*, it simply means that the function is returning a monad, i.e., some type `F[A]`

rather than the raw type `A`

.

## Notes

In my programming life I need to move on to other topics, so I wrote this post quickly. It would be more effective if I showed you how to write `flatMap`

and `map`

functions in a monad, but I already did that in Functional Programming, Simplified, so I won’t repeat that here.

A few other notes:

- I oversimplified the definition of
*monad*in that discussion. There are formal rules about monads that are important, and I discuss those in Functional Programming, Simplified. But a useful simplification is that any class that implements`map`

is a*functor*, and any class that further implements`flatMap`

(in addition to`map`

) is a*monad*. - In the preceding discussion I used
`Option`

for my examples, but you can also use instances of`Try`

or`Either`

, if you prefer. - I could have written
`toInt`

shorter (as shown below) but I wanted to clearly show the Option/Some/None types in the function body:

`def toInt(s: String): Option[Int] = Try(Integer.parseInt(s.trim)).toOption`

Finally, in a shameless plug, if you’re interested in functional programming but parts of that conversation didn’t make sense, I encourage you to read my book, Functional Programming, Simplified:

Back to top
## Comments

## Thank you

The last time i had the feel to really understand a paradigma was when i read "Elegant Objects" by Yegor Bogayenko. Reading your book and this blog i have similar feelings now in the context of functional programming again.

## fp-simplified

After reading this excellent post, I was compelled to buy a copy of pf-simplified. You have a real gift for explaining things, something we need much more of in the Scala world. I have been using Scala for over 10 years, and I am still struggling with grokking it.

## Add new comment