Scala ひと巡り : シーケンス内包表記 (Sequence Comprehensions)

Scala は、シーケンス内包表記式に対して簡単な表記法を提供します。内包表記は for enums yield e の形をしています。ここで enums は、セミコロンで分離された列挙子のリストを参照します。列挙子は、新しい変数を導入する生成子、あるいは、フィルタです。内包表記は、列挙子 enum によって生成された各束縛にごとに、本体 e を評価し、それら値のシーケンスを返します。

次は 1 つの例です:

object ComprehensionTest1 extends Application { def even(from: Int, to: Int): List[Int] = for (i <- List.range(from, to) if i % 2 == 0) yield i Console.println(even(0, 20)) }

関数 even 中の for 式は Int 型の新しい変数 i を導入し、それをリスト List(from,from + 1,...,to - 1) の全ての値へ次々に束縛します。ガード if i % 2 == 0 は、(式 i だけからなる)本体が偶数の場合のみ評価されるよう、全ての奇数をフィルターします。最終的に、for 式全体は偶数のリストを返します。

プログラムは次を出力します:

List(0, 2, 4, 6, 8, 10, 12, 14, 16, 18)

次はより複雑な例で、その合計が与えられた値 v と等しい、0 から n - 1 までの数の対をすべて計算します。:

object ComprehensionTest2 extends Application { def foo(n: Int, v: Int) = for (i <- 0 until n; j <- i + 1 until n if i + j == v) yield Pair(i, j); foo(20, 32) foreach { case (i, j) => println("(" + i + ", " + j + ")") } }

この例は、内包表記がリストに制限されないことを示しています。前のプログラムは、代わりにイテレータを使っています。(適切な型をもつ) 操作 filter、map そして flagMapをサポートするすべてのデータ型は、シーケンス内包表記中で使えます。

次はプログラムの出力です:

(13, 19) (14, 18) (15, 17)

シーケンス内包表記で Unitを返す、特別の形式もあります。そこでは、生成子のリストとフィルターから生成される束縛は、副作用を起こさせるために使われます。そのような シーケンス内包表記を利用するには、プログラマはキーワード yield を取り除かなければなりません。

次は、前のものと等価ではあるが Unit を返す、特別な for 内包表記を使うプログラムです。:

object ComprehensionTest3 extends Application { for (i <- Iterator.range(0, 20); j <- Iterator.range(i + 1, 20) if i + j == 32) println("(" + i + ", " + j + ")") }