for comprehension(for内包表記)

について・・・

forの中でyieldが使われるとfor構文全体がコレクション(ないしはイテレータ)として値を持ち、
個々の要素がyieldの右辺の値となる。
これを「for comprehension(for内包表記)」という。


http://www.thinkit.co.jp/cert/article/0711/4/3/2.htm

やっと理解した><

たとえば・・・

scala> for ( i <- 1 to 9 if (i != 5) ) yield (i,i)
res4: Seq.Projection[(Int, Int)] = RangeFM((1,1), (2,2), (3,3), (4,4), (6,6), (7,7), (8,8), (9,9))

といった感じで、これは。

scala> (1 to 9).filter(i => i != 5).map(i => (i,i))
res5: Seq.Projection[(Int, Int)] = RangeFM((1,1), (2,2), (3,3), (4,4), (6,6), (7,7), (8,8), (9,9))

と同じこと。
というか、内部的にこれに変換されている。
一応確認してみよう。

>scala -Xprint:namer fortest.scala

[[syntax trees at end of namer]]// Scala source: (virtual file)
package <empty> {
  final object Main extends scala.ScalaObject {
    def <init>() = {
      super.<init>();
      ()
    };
    def main(argv: Array[String]): Unit = {
      val args = argv;
      1.to(9).filter(((i) => i.$bang$eq(5))).map(((i) => scala.Tuple2(i, i)))
    }
  }
}

となる。


ほかも

scala> (for (c <- 'a' to 'z') yield (c)) toList
res19: List[Char] = List(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z)

などもOK。

調子に乗ってやってみた

scala> for (i <- 1 to 2 ; c <- 'a' to 'c') yield (i,c)
<console>:5: error: type mismatch;
 found   : Iterator[(Int, Char)]
 required: Iterable[?]
       for (i <- 1 to 2 ; c <- 'a' to 'c') yield (i,c)
                          ^

は、失敗するのだけれど。

scala> for (i <- 1 to 2 ; c <- ('a' to 'c').toList) yield (i,c)
res35: Seq.Projection[(Int, Char)] = RangeG((1,a), (1,b), (1,c), (2,a), (2,b), (2,c))

なら、うまくいく。