Search code examples
scalafor-loopnested-loops

How does a for loop with multiple generators work in Scala?


I'm new to Scala and coming at this from an imperative background but I'd like to understand it in functional terms. I'm very confused about the behavior of the following code snippets.

val res = for {
  i <- 1 to 2
  j <- 1 to 2
} yield (i, j)

println(s"res is $res")

This code will print res is Vector((1,1), (1,2), (2,1), (2,2)) as expected. However modifying the above slightly to

val res = for {
  i <- 1 to 2
  j <- i to 0
} yield (i, j)

println(s"res is $res")

prints res is Vector()

Why doesn't the second version of the loop yield Vector((1,1), (1,0), (2,2), (2,1), (2,0))?

This behavior has a significant impact on my ability to loop over 2D matrices using indices in Scala. In general, how could one loop over ONLY the upper triangular portion of a matrix in an idiomatic way while keeping track of the row and column indices?


Solution

  • Let the REPL tell you.

    scala> 1 to 2
    res0: scala.collection.immutable.Range.Inclusive = Range 1 to 2
    
    scala> 1 to 0
    res1: scala.collection.immutable.Range.Inclusive = empty Range 1 to 0
                                                       ^^^^^
    

    A Range won't go downward unless you tell it to.

    val res = for {
      i <- 1 to 2
      j <- i to 0 by -1
    } yield (i, j)
    //res: IndexedSeq[(Int, Int)] = Vector((1,1), (1,0), (2,2), (2,1), (2,0))