In this section, we’re going to explore a few functions that either operate on monadic values or return monadic values as their results (or both!). Such functions are usually referred to as monadic functions.

Unlike Haskell’s standard `Monad`, Cats’ `Monad` is more granularly designed with the hindsight of weaker typeclasses.

• `Monad`
• extends `FlatMap` and `Applicative`
• extends `Apply`
• extends `Functor`

Here there’s no question that all monads are applicative functors as well as functors. This means we can use `ap` or `map` operator on the datatypes that form a monad.

#### flatten method

LYAHFGG:

It turns out that any nested monadic value can be flattened and that this is actually a property unique to monads. For this, the `join` function exists.

In Cats, the equivalent function called `flatten` on `FlatMap`. Thanks to simulacrum, `flatten` can also be injected as a method.

``````@typeclass trait FlatMap[F[_]] extends Apply[F] {
def flatMap[A, B](fa: F[A])(f: A => F[B]): F[B]

/**
* also commonly called join
*/
def flatten[A](ffa: F[F[A]]): F[A] =
flatMap(ffa)(fa => fa)

....
}
``````

Since `Option[A]` already implements `flatten` we need to make an abtract function to turn it into an abtract type.

``````import cats._, cats.syntax.all._

def join[F[_]: FlatMap, A](fa: F[F[A]]): F[A] =
fa.flatten

join(1.some.some)
// res0: Option[Int] = Some(value = 1)
``````

If I’m going to make it into a function, I could’ve used the function syntax:

``````FlatMap[Option].flatten(1.some.some)
// res1: Option[Int] = Some(value = 1)
``````

#### filterM method

LYAHFGG:

The `filterM` function from `Control.Monad` does just what we want! … The predicate returns a monadic value whose result is a `Bool`.

Cats does not have `filterM`, but there’s `filterA` on TraverseFilter.

#### foldM function

LYAHFGG:

The monadic counterpart to `foldl` is `foldM`.

I did not find `foldM` in Cats, so implemented it myself, but it wasn’t stack-safe. Tomas Mikula added a better implementation and that got merged as #925:

``````  /**
* Left associative monadic folding on `F`.
*/
def foldM[G[_], A, B](fa: F[A], z: B)(f: (B, A) => G[B])(implicit G: Monad[G]): G[B] =
foldLeft(fa, G.pure(z))((gb, a) => G.flatMap(gb)(f(_, a)))
``````

Let’s try using this.

``````def binSmalls(acc: Int, x: Int): Option[Int] =
if (x > 9) none[Int] else (acc + x).some

(Foldable[List].foldM(List(2, 8, 3, 1), 0) {binSmalls})
// res2: Option[Int] = Some(value = 14)

(Foldable[List].foldM(List(2, 11, 3, 1), 0) {binSmalls})
// res3: Option[Int] = None
``````

In the above, `binSmalls` returns `None` when it finds a number larger than 9.