[scala][java][tutorial] Scala本を読む 9

制御の抽象化

  • 9.1 重複するコードの削減

例:?末尾が特定の文字列で終わるファイル、?先頭が特定の文字列で始まるファイル、?正規表現にマッチしたファイル名 を探す関数を作るとする。
フォルダ内のファイルを列挙し、一つずつファイル名がマッチするかチェックするような動作になるだろう。

Javaだと、Stringを引数にとり、booleanを返すinterfaceを定義し、そこに?〜?の動作をするように実装した無名クラスを利用する。
Scalaでは関数値(function values)を引数にとることでコードを少なくできる。

object FileMatcher {
  private def filesHere = (new java.io.File(".")).listFiles
  def filesEnding(query: String)) = 
    for (file <- filesHere; if file.getName.endsWith(query))
      yield file
}

マッチする部分をさらに縮めて
  def filesEnding(query: String) =
    filesMatching(query, _.endsWith(_))

とできる。
javaのinterface方式では「コードの重複を取り除けるが、同時に同じくらいかそれ以上の量の新しいコードを増やしてしまう」らしい。
だからめんどくさい気がするのか。なるほど。

  • 9.2 クライアントコードの単純化

コレクションに「特定の条件を満たすものがあればtrue」を返すExsits関数など。
判断部分だけを渡せばOKなのでコードが少なくて済む。

  • 9.3 カリー化

前に出てきた気がするけど、なんとなくの説明。
f(x,y)⇒F(x)(y) とする。
引数xをとって、引数yをとる関数を返す。←の関数は引数yを入れるとf(x,y)と同じ結果を返す。

  • 9.4 新しい制御構造
def withPrintWriter(file: File, op: PrintWriter => Unit){
  val writer = new PrintWriter(file)
  try {
    op(writer)
  } finally {
     writer.close();
  }
}
を、カリー化して、さらに「引数を一つだけ渡すメソッドは{}を使ってよいルール」を使うと
def withPrintWriter(file: File)(op: PrintWriter => Unit) {
  val writer = new PrintWriter(file)
  ・・・
}
とかけて、

val file = new file("sample.txt");
withPrintWriter(file){
  writer => writer.println(new java.util.Date);
}

確かに、while(){}みたいにかける。「新しい制御構造」。

  • 9.5 名前渡しパラメータ
def byNameAssert(predicate: => Boolean) =
  if(assertionEnabled && !predicate)
    throw new AssertionError
本当は
def byNameAssert(predicate: () => Boolean)〜

これでbyNameAssert(() => z>10)でなくbyNameAssert(z > 10)とできる。
byNameAssert(Boolean)との違いは、中身が遅延評価されるということ。