Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to understand the "println" statements in both `for` and `yield`

Scala code:

val list = List(1, 2, 3)
for {
  item <- list
  _ = println("1111111111")
} yield {
  println("XXXXXXXXX")
  item + 1
}

I expected it to print:

1111111111
XXXXXXXXX
1111111111
XXXXXXXXX
1111111111
XXXXXXXXX

But actually it prints:

1111111111
1111111111
1111111111
XXXXXXXXX
XXXXXXXXX
XXXXXXXXX

I can't understand this because I thought the code will be expanded like:

val list = List(1, 2, 3)
list.map { item =>
  val _ = println("1111111111")
  println("XXXXXXXXX")
  item + 1
}

Which should print XXXXXXXX just before 11111111 in each loop.

like image 970
Freewind Avatar asked Mar 19 '23 17:03

Freewind


2 Answers

The Scala specification, in section 6.19 "For Comprehensions and For Loops", clearly describes the behavior:

A generator p <- e followed by a value definition p' = e' is translated to the following generator of pairs of values, where x and x' are fresh names:

(p, p') <- for ( x@p <- e ) yield { val x'@p' = e' ; (x, x') }

As an example, the code

for {x <- xs; y = 1} yield {x+y}

is desugared to

xs.map{x => val y = 1; (x,y)}.map{ case (x,y) => x+y}

In your case it would be

xs.map{x => val x$1 = println("1"); (x,x$1)}.map{ case (x,_) => x+1}

where the second value of the tuple is thrown away.

like image 129
kiritsuku Avatar answered Mar 22 '23 20:03

kiritsuku


What you're seeing is the following desugar of the map function:

def map[B](f: A => B)(implicit cbf: CanBuildFrom[B, List[A], List[B]]): List[B] ={
  val b = new ListBuffer[B]
  var xs = this
  while(!xs.isEmpty){
    b += f(xs.head) //calls "f" here which activates the println
    xs = xs.tail
  }
  b result ()
}

which actually first iteratively creates each element of the new list by successively calling f and then it returns that created list. Do note that f in this case is not what is in the yield. That is another function which is called in addition to what is in the for comprehension body.

Hence, it's going to print out "1111111" before it ever returns the results you'd like to see followed by what is in the yield block.

like image 26
wheaties Avatar answered Mar 22 '23 19:03

wheaties