Example10.3

10.3 For 内包表記の変換

すべての for 内包表記は3つの高階関数 map, flatMap, filter で表現できます。これが翻訳のスキーム(枠組み)であり、Scala コンパイラも使っています。

• 単純な for 内包表記

for (x <- e) yield e' 

これは次のように翻訳されます。

e.map(x => e') 

• for 内包表記

for (x <- e if f; s) yield e' 

ただし f はフィルタで、s は (空でも良い) ジェネレータあるいはフィルタの列。これは次のように翻訳されます。

for (x <- e.filter(x => f); s) yield e' 

そして後者の式に対して翻訳が続きます。

• for 内包表記

for (x <- e; y <- e'; s) yield e'' 

ただし s は (空でも良い) ジェネレータあるいはフィルタの列。これは次のように翻訳されます。

e.flatMap(x => for (y <- e'; s) yield e'') 

そして後者の式に対して翻訳が続きます。

たとえば、「和が素数になる整数の組」を例にとると、

for { i <- range(1, n) 
      j <- range(1, i) 
      if isPrime(i+j) 
} yield {i, j} 

この式を翻訳すると次が得られます。

range(1, n) 
  .flatMap(i => 
    range(1, i) 
      .filter(j => isPrime(i+j)) 
      .map(j => (i, j))) 

逆に、関数 map, flatMap, filter を for 内包表記で表すこともできます。3つの関数を今度は for 内包表記を使って実装してみます。

object Demo { 
  def map[A, B](xs: List[A], f: A => B): List[B] = 
    for (x <- xs) yield f(x) 

  def flatMap[A, B](xs: List[A], f: A => List[B]): List[B] = 
    for (x <- xs; y <- f(x)) yield y 

  def filter[A](xs: List[A], p: A => Boolean): List[A] = 
    for (x <- xs if p(x)) yield x 
}

驚くことではありませんが、Demo.map の本体の for 内包表記の翻訳は、クラス List の map を呼び出します。同様に、Demo.flatMap と Demo.filter は、クラス List の flatMap と filterの呼び出しへ翻訳されます。

演習 10.3.1  次の関数を for を用いて定義しなさい。

def flatten[A](xss: List[List[A]]): List[A] = 
  (xss :\ (Nil: List[A])) ((xs, ys) => xs ::: ys) 

演習 10.3.2  次を高階関数を用いて翻訳しなさい。

for (b <- books; a <- b.authors if a startsWith "Bird") yield b.title 
for (b <- books if (b.title indexOf "Program") >= 0) yield b.title 

名前:
コメント:

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2011年02月24日 08:50
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。