FP Fundamentals: 3. For Comprehensions
May 02, 2020
This article is a part of a series of small articles explaining the most fundamental functional programming design patterns.
Prefer for-comprehension over the chain of map / flatMap / filter / withFilter in most cases (unless it is a single map or filter). Not only is the code in this form easier to read, it is also easier to extend it and to move things around. I hope it is apparent from the examples above. Note: you can usually simplify a chain of filter and map into one call of collect.
Analysing the code
sealed trait Result[+A] {
def foreach(f: A => Unit): Unit = {
this match {
case Failure(reason) => ()
case Success(value) => f(value)
}
}
def map[B](f: A => B): Result[B] = {
this match {
case Failure(reason) => Failure(reason)
case Success(value) => Success(f(value))
}
}
def flatMap[B](f: A => Result[B]): Result[B] = {
this match {
case Failure(reason) => Failure(reason)
case Success(value) => f(value)
}
}
}
final case class Success[A](value: A) extends Result[A]
final case class Failure[A](reason: String) extends Result[A]
for { a <- Success(3) } println(a)
Success(3).foreach(a => println(a))
for { a <- Success(3) } yield a * a
Success(3).map(a => a * a)
for { a <- Success(3) ; b <- Success(4) } yield a * b
Tuple(Success(3), Success(4)).map((a, b) => a * b)