Some useful monadic functions 

Learn You a Haskell for Great Good says:

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 of weaker typeclasses.

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 


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.

scala> import cats._, cats.instances.all._, cats.syntax.flatMap._
import cats._
import cats.instances.all._
import cats.syntax.flatMap._

scala> :paste
// Entering paste mode (ctrl-D to finish)
object Catnip {
  implicit class IdOp[A](val a: A) extends AnyVal {
    def some: Option[A] = Some(a)
  def none[A]: Option[A] = None
import Catnip._

// Exiting paste mode, now interpreting.

defined object Catnip
import Catnip._

scala> def join[F[_]: FlatMap, A](fa: F[F[A]]): F[A] =
join: [F[_], A](fa: F[F[A]])(implicit evidence$1: cats.FlatMap[F])F[A]

scala> join(1.some.some)
res0: Option[Int] = Some(1)

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

scala> FlatMap[Option].flatten(1.some.some)
res1: Option[Int] = Some(1)

I tried using flatten method for an Xor of an Xor value, but it didn’t seem to work:

scala> import

scala> val xorOfXor = Xor.right[String, Xor[String, Int]](Xor.right[String, Int](1))
xorOfXor:[String,[String,Int]] = Right(Right(1))

scala> xorOfXor.flatten
res2:[String,Int] = Right(1)

filterM method 


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 


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.

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

scala> (Foldable[List].foldM(List(2, 8, 3, 1), 0) {binSmalls})
res3: Option[Int] = Some(14)

scala> (Foldable[List].foldM(List(2, 11, 3, 1), 0) {binSmalls})
res4: Option[Int] = None

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