flatMap explained

Understanding how map works is pretty easy. It doesn’t need a second thought. In the contrary flatMap usually needs a bit of thinking to realize/remember how it works. In this post I’ll try to give a schematic explanation of the difference of flatMap & map.

Basically, map & flatMap result to the same thing. They take a monad & return a monad with transformed values.

monad transformations

The difference between them lays in the transformation function. Map’s transformation function takes a value & returns a value where flatMap takes a value & returns a monad with the transformed value.

map

flatMap

Now you will ask me why is it called flatMap then? Well .. it’s called flatMap because if you use map on a function that returns a monad, you get a “doublemonad (see drawing below). So in that context, flatMap “flattens out” the result 🙂

issue with map

And that situation (double monad) happens quite often! For example, if you have a booking that has an optional user. And the optional user has an optional email. And you want to write a method getEmail() that gives you the email option of a booking, how would you do it with map?

booking : Booking
booking.user : Option[User]      
booking.user.email : Option[String]
def getEmail(booking: Booking) : Option[String] = ???

If you use map for it, you’ll have to do something like that (mainly because booking.user.map(_.email) returns an Option[Option[String]]):

def getEmail(booking: Booking) = booking.user.map(_.email).getOrElse(None)

This is where flatMap becomes useful. Due to the fact that flatMap’s transformation function is returning a monad, we kind of right away get the inner monad!:

def getEmail(booking: Booking) booking.user.flatMap(_.email)

And that’s it! Do you get it now why is it called flatMap? Hope this blog post helps you remember it 🙂 Have a nice day!

Advertisements

Try, the new monad in Scala 2.10

Today I tried for the first time Scala’s Try monad. I used it twice already and I’m sure I’ll use a lot more times!

Here is how I used it the first time. I wanted to parse some CSV data into a sequence of case classes. And of course, with input data you never know what can go wrong. I didn’t really want to handle the error, I just wanted to know if it was parsed correctly or not. Therefore I used an Option to return either Some(result) or None.

Here is the code for the attempt with Option:

def parseCSV(csv : String) = {
  try {
    Some {
      csv.split("\n").map { line =>
        val tokens = line.split(";")
        ActivityData(tokens(0).toLong, tokens(1).toInt, tokens(2).toInt, tokens(3).toLong)
      }
    }
  } catch {
    case _ : Throwable => None
  }
}

A bit complicated isn’t it? Using this function is cool (just as with every other Option) but actually reading it is painful. It’s just too messy with that try catch. Is there a better way of doing this?

Well, there comes the Try monad from scala.util package to save the situation!

def parseCSV(csv : String) = Try {
  csv.split("\n").map { line =>
    val tokens = line.split(";")
    ActivityData(tokens(0).toLong, tokens(1).toInt, tokens(2).toInt, tokens(3).toLong)
  }
}

Look at this! Wow! This is neat! Just surround your code with Try and that’s it!

And the best part, you can use it exactly the same way as you would use the Option monad (dah .. that’s what are monads all about).

parseCSV(csvdata).map { entries =>
  //do something with the data
}.getOrElse {
  BadRequest("Invalid CSV Data")  //this is Play Framework specific (returns a 400 HTTP response with a message)
}

Note: For those who are wondering how does this work, the Try monad returns Success(something) if everything was calculated without any exceptions and Failure(error) if an error was thrown while executing the argument of Try().

Note (deep): Try takes its argument by-name (not by-value), therefore it can execute it within a try, catch the exception and return either Success or Failure. Isn’t Scala a super powerful awesome language? Yes it is!