Search code examples
scalascala-collectionsfor-comprehension

Return type of Scala for/yield


I'm reading through Scala for the Impatient and I've come across something that's got me scratching my head.

The following returns a String:

scala> for ( c<-"Hello"; i <- 0 to 1) yield (c+i).toChar
res68: String = HIeflmlmop

But this returns a Vector:

scala> for (i <- 0 to 1; c <- "Hello") yield (c + i).toChar
res72: scala.collection.immutable.IndexedSeq[Char] = Vector(H, e, l, l, o, I, f, m, m, p)

The text preceding these two examples reads...

"When the body of the for loop starts with yield, then the loop constructs a collection of values, one for each iteration...This type of loop is called a for comprehension. The generated collection is compatible with the first generator.

If the generated collection is compatible with the first generator, then why isn't the second example returning a type of Range, as in the following:

scala> val range = 0 to 1
range: scala.collection.immutable.Range.Inclusive = Range(0, 1)

Or am I misinterpreting entirely what the text means by, "...the generated collection is compatible with the first generator."


Solution

  • for-comprehensions are desugared to a series of map, flatMap and filter operations.

    When you use map on a Range, you get a Vector output:

    scala> 0 to 2 map (x => x * x)
    res12: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 4)
    

    This is because a Range is a very simple sort of collection, that is essentially just two three numbers: a start value, an end value and a step. If you look at the result of the mapping above, you can see that the resulting values cannot be represented by something of the Range type.