# Scala For Comprehension Tricks

For comprehensions are beautiful.

Basic syntax & rules:

• backwards arrows call flatmap
• equal sign is basic assignment(you do not use val or var because everything is a val inside a for comprehension)
• you can filter using an if at the end of the line like python list comprehensions
• the yield at the end calls map

Simple example, let’s say we get a epoch string and we want to turn it into a date.

`val epoch = "123123123"for {    epochInt <- Try(epoch.toInt)    time <- Try(Datetime.fromEpoch(epochInt))} yield timethis is equivalent toTry(epoch).flatMap { epochInt =>    Try(Datetime.fromEpoch(epochInt)).map { time =>        time    }}`

Every <- must be called on the same monad. The underlying type does not matter

`for {    number <- Option(2)    string <- Try(number.toLong)} yield string// Very bad >:( because you can't mix option and try`

Fortunately Try and Option are easily interchangeable

`for {    number <- Option(2)    string <- Try(number.toLong).toOption} yield string`

This leads me to my next point which is that it is usually trivial to make conversions between stuff like Option, Try, Either, etc. For example, Either to Option would simply be.

`implicit class EitherUtil[L,R](either: Either[L,R]) {    def toOption =        either match {            case Left(x) => None            case Right(x) => Some(x)        }}// The downside is that you often lose type information when        // converting one to another. None is not very good for debugging`

However, sometimes it gets tricky when you want to mix in stuff like Seq or Future. Let’s say you want take a Option[Int] and split it into its digits. As in Some(123) -> Seq(1,2,3). You would have to first map into the Option, turn it into a string, then map on the character like such.

`val optNumber = Some(123)for {    number <- optNumber    char <- number.toString.split("")    digit <- Try(char.toInt).toOption} yield digit// BAD`

But you just violated the no mixing rule by flatmapping on Seq and Option so usually what you would do here is collect the second and third flatmaps together like such.

`val optNumber = Some(123)def numberToDigit: Int => Option[Seq[Int]] = Some(_.toString.split("").flatMap(Try(_.toInt).toOption))for {    number <- optNumber    digits <- numberToDigit(number)} yield digits`

Ok, that was messy, but the idea is that if your types look something like this: Option -> List -> Option -> Future -> Option, anything downstream of the List type is unusable in the for comprehension because you can’t flatmap on the list. This will force you to move some logic around and play with the types, but it will produce very readable code. Eventually, what we really want is code that looks like this.

`// F[_] is a monad like Option, Try, etcprivate def doA(F[A] input): F[B] = somethingprivate def doB(F[B] input): F[C] = somethingprivate def doC(F[C] input): F[D] = somethingdef magic(input: A): F[D] = {  for {    a <- doA(input)    b <- doB(a)    c <- doC(b)  } yield c}`

However, there is one special case where you have something that looks like Future -> Option -> Future -> Option -> Future -> Option. This happens all the time when you are trying to chain network calls asynchronously. There is this really neat type called the OptionT that lets you collapse the above into a 5 line for comprehension. I wrote a little on it too here https://medium.com/@scalaisfun/optiont-and-eithert-in-scala-90241aba1bb7.