Scala Lesson 36 – For Comprehensions | Dataplexa

For-Comprehensions

In this lesson, you will learn about for-comprehensions in Scala. They provide a clean, readable syntax for working with collections and monadic types such as Option, Either, and Try.

For-comprehensions are not loops in the traditional sense. They are a powerful abstraction built on top of map, flatMap, and withFilter.


Why Use For-Comprehensions?

Without for-comprehensions, chaining multiple transformations can quickly become hard to read due to nested calls.

  • Improves readability
  • Reduces nesting
  • Makes data flow explicit
  • Works uniformly across many Scala types

Basic Syntax

A simple for-comprehension iterates over a collection and produces a new one.

val numbers = List(1, 2, 3, 4)

val doubled = for (n <- numbers) yield n * 2
println(doubled)

This is equivalent to using map.


Multiple Generators

You can use multiple generators to create combinations of values.

val letters = List("A", "B")
val numbers = List(1, 2)

val pairs = for {
  l <- letters
  n <- numbers
} yield (l, n)

println(pairs)

Each generator runs for every value of the previous one.


Using Guards (Filters)

Guards allow you to filter values inside a for-comprehension.

val evenNumbers = for {
  n <- List(1, 2, 3, 4, 5, 6)
  if n % 2 == 0
} yield n

println(evenNumbers)

Guards are translated into withFilter calls.


For-Comprehensions with Option

For-comprehensions work seamlessly with Option. If any value is None, the entire result becomes None.

val result = for {
  a <- Some(10)
  b <- Some(5)
} yield a + b

println(result)

This avoids explicit null or None checks.


For-Comprehensions with Either

You can chain error-prone computations using Either.

def parseInt(s: String): Either[String, Int] =
  if (s.forall(_.isDigit)) Right(s.toInt)
  else Left("Invalid number")

val result = for {
  a <- parseInt("10")
  b <- parseInt("2")
} yield a / b

println(result)

If any step fails, the computation short-circuits with a Left.


For-Comprehensions with Try

For-comprehensions also work with Try, making exception handling concise.

import scala.util.Try

val result = for {
  a <- Try(10 / 2)
  b <- Try(a * 3)
} yield b

println(result)

Desugaring: What the Compiler Does

A for-comprehension is translated into method calls. For example:

for {
  x <- list
  y <- anotherList
} yield x + y

Is equivalent to:

list.flatMap(x =>
  anotherList.map(y => x + y)
)

Understanding this helps you reason about performance and behavior.


When to Use For-Comprehensions

Use for-comprehensions when:

  • Chaining multiple dependent operations
  • Working with Options, Either, or Try
  • Transforming collections cleanly
  • Readability matters

📝 Practice Exercises


Exercise 1

Use a for-comprehension to square all numbers in a list.

Exercise 2

Chain two Option values using a for-comprehension.

Exercise 3

Use a guard to filter odd numbers.


✅ Practice Answers


Answer 1

val squares = for {
  n <- List(1, 2, 3, 4)
} yield n * n

Answer 2

val result = for {
  a <- Some(5)
  b <- Some(10)
} yield a + b

Answer 3

val odds = for {
  n <- List(1, 2, 3, 4, 5)
  if n % 2 != 0
} yield n

What’s Next?

In the next lesson, you will explore Error Handling in Scala and learn best practices for building robust and reliable applications.