Higher-Order Functions & For-Comprehensions

Any type with map, flatMap, (withFilter), (foreach) works in for-comprehensions: Option, Either, Try, Future, IO, parsers, your own types.

18.1 For-comprehensions desugar to map/flatMap/withFilter

Any type with map, flatMap, (withFilter), (foreach) works in for-comprehensions: Option, Either, Try, Future, IO, parsers, your own types.

for
  x <- List(1, 2, 3)
  y <- List("a", "b")
  if x > 1
yield (x, y)

// is translated to
List(1, 2, 3).withFilter(_ > 1).flatMap(x => List("a", "b").map(y => (x, y)))

18.2 Mixing generators and definitions

All generators must be the same "container" type (you can't mix Option and List without conversion).

for
  user <- findUser(id)          // Option[User]
  name = user.name.trim         // plain value binding
  email <- user.email           // Option[String]
yield s"$name <$email>"

18.3 Writing your own monadic type

case class Box[A](value: A):
  def map[B](f: A => B): Box[B] = Box(f(value))
  def flatMap[B](f: A => Box[B]): Box[B] = f(value)

for a <- Box(1); b <- Box(2) yield a + b   // Box(3)

18.4 Function-returning functions & currying in practice

def filterBy[A](pred: A => Boolean)(xs: List[A]): List[A] = xs.filter(pred)
val positives = filterBy[Int](_ > 0)
positives(List(-1, 2, 3))