# Scala Cats library for dummies- part 4

This article will center on cats library monad type class, but before we proceed, it will be nice to have a good understanding of the `flatMap` function in the standard scala collections. `FlatMap` is basically two functions in one i.e `map` and `flatten`. As an example, say we want to multiply the elements of two(2) Lists of integers and return a single list, one approach is to use the map function of the first List to iterate over the second List then combine(flatten) the final result.

`scala> val first = List(2, 5)first: List[Int] = List(2, 5)`
`scala> val second = List(4, 8)second: List[Int] = List(4, 8)`
`scala> first.map( e1 => second.map(e2 => e1 * e2))res0: List[List[Int]] = List(List(8, 16), List(20, 40))`
`scala> res0.flatten res1: List[Int] = List(8, 16, 20, 40) `

Notice how we used flatten to merge `List[List[Int]]` into `List[Int]. `Flatten can also be used for nested `option` types. lets see a very trivial example.

`scala> val a = Option(5)a: Option[Int] = Some(5)`
`scala> def intToSome(x:Int) = Some(x) intToSome: (x: Int)Some[Int]`
`scala> a.map( o => intToSome(o))res5: Option[Some[Int]] = Some(Some(5))`
`scala> res5.flattenres6: Option[Int] = Some(5)`
`scala> val a = Option(5)a: Option[Int] = Some(5)`
`scala> def intToSome(x:Int) = Some(x)intToSome: (x: Int)Some[Int]`
`scala> a.flatMap( x => intToSome(x))res0: Option[Int] = Some(5)`
`scala> first.flatMap( f => second.map(s => f * s))res2: List[Int] = List(8, 16, 20, 40)`

In both examples `flatten` function was used to merge the final result into a single data type. The flatten function takes a nested context F[F[A]] to return F[A]. We can however use the `flatMap` function in the standard library to achieve the same computation when ever we find ourselves writing `map` and `flatten` expressions.

`F[F[A]]             => F[A]Option[Option[Int]] => Option[Int]List[List[Int]]     => List[Int]`

Below is the signature of the `flatMap` function

`def flatMap[B](f: A => F[B]): F[B]`

Remember, we discussed Applicative `pure` function back then in part 3 , now, adding `flatMap` to the Applicative type class gives you a Monad( any instance that have the `pure` and `flatMap` methods).

We have already seen `flatMap` in action in our previous List and Option examples above, however, monads are in almost everywhere in all scala collections and data types(Set, Vector, Array, Map , Future* etc ), even though there is no concrete class or trait called monad in the standard scala language.

Lets have a look at an example of monad usage : say we have a student school management application and we want to implement a module that will compute the individual performance of a student for a particular session. First, we need to retrieve the student profile information, then retrieve all the courses he/she registered for that session, and finally retrieve all the grades of these courses.

`case class Grade(id:Int, studentId:Int, grade: String)case class Student(id: Int, name: String)case class StudentCourse(id:Int,                          studentId: Int,                         courseId:  Int)`
`object StudentService{    def getStudentById(id: Int): Option[Student] = {}}`
`object StudentCoursesService{  def getCourses(student: Student): Option[List[StudentCourse]]={}}`
`object StudentGrades{  def getGrades(lc: List[StudentCourse]): Option[List[Grade]]={}}`

Looking carefully at the return types of the service methods(options), we can simply flatmap everything.

`val studentGrade = StudentService.getStudentById(id)                                 .flatMap(getCourses)                                 .flatMap(getGrades)`

Alternatively, we can use the for-comprehension which is a composition of map and flatMap.

`val studentGrade = for {    student <- getStudentById(id)    courses <- getCourses(student)    grades  <- getGrades(courses)}yield grades`

if we had to do this without using monads we will having a lot of if/then/else statement or nested loops flying everywhere (where fixing a bug could possibly give you two free bugs :{ ).

Libraries that are fully non-blocking with asynchronous I/O operation usually encapsulated their return types in types like `future`s , one example of such libraries is reactivemongo. When using such libraries you will likely have to use the`future` ‘s flatmap method in composing multiple operations together.

Essentially,`flatMap` is the most fundamental function of Monad and authors of cats library also built its monad based on this principle — by using `flatMap` and `pure` to implement `flatten` and `map`, however, they also added another requirement to all cats library monad implementation, called tailRecM ( Tail recursive Monad), the reason behind this additional requirement is to make monadic recursion stack safe( since monadic recursion are quite common and a poor implementation could lead to stack overflow on the jvm ).

Below is a `Monad` implementation for `Option`.

``import scala.annotation.tailrecimplicit val optionMonad = new Monad[Option] {  def flatMap[A, B](fa: Option[A])(f: A => Option[B]): Option[B] = fa.flatMap(f)  def pure[A](a: A): Option[A] = Some(a)  @tailrec  def tailRecM[A, B](a: A)(f: A => Option[Either[A, B]]): Option[B] = f(a) match {    case None              => None    case Some(Left(nextA)) => tailRecM(nextA)(f) // continue the recursion    case Some(Right(b))    => Some(b)            // recursion done  }}``

In conclusion, I deliberately did not discuss that monad laws as what we have learnt is enough for you kick start your journey to the land of monads! However, Monads is not everything, but having it in your tool box is definitely a thing to work in the functional world of scala.

Lets take a break from here, but don't hesitate to buzz me if you don't understand any aspect of this writeup. Our next discuss will be on the OptionT which is also a monad.

If you like this writeup, click the💚 below so more people can see it here on Medium.