1. (手始めの)高階関数でないバージョン。
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 filesContaining(query: String) =
for(file <- filesHere; if file.getName.contains(query))
yield file
def filesRegex(query: String) =
for(file <- filesHere; if file.getName.matches(query))
yield file
}
2. ヘルパメソッド(マッチングの関数をとる高階関数)導入
filesEnding, filesContaining, filesRegex で重複していた for(...) yield ... をヘルパメソッド filesMatching にくくりだします。
object FileMatcherHO {
private def filesHere = (new java.io.File(".")).listFiles
// マッチング処理を行うヘルパメソッド
private def filesMatching(query: String, matcher: (String, String) => Boolean) = {
for(file <- filesHere; if matcher(file.getName, query))
yield file
}
// filesMatching にクエリ文字列とマッチング関数を渡す
def filesEnding(query: String) =
filesMatching(query, (name:String,query:String) => name.endsWith(query))
def filesContaining(query: String) =
filesMatching(query, (name:String,query:String) => name.contains(query))
def filesRegex(query: String) =
filesMatching(query, (name:String,query:String) => name.matches(query))
}
2-a. プレースホルダー導入
filesEnding, etc. の第2引数で与える無名関数は引数の型が省略できます(コンパイラが型推論してくれるので)。
def filesEnding(query: String) =
filesMatching(query, (name,query) => name.endsWith(query))
さらに、プレースホルダーが使えてもっと短くなります。
object FileMatcherHOPlaceHolder {
private def filesHere = (new java.io.File(".")).listFiles
private def filesMatching(query: String, matcher: (String, String) => Boolean) = {
for(file <- filesHere; if matcher(file.getName, query))
yield file
}
// プレースホルダー使用
def filesEnding(query: String) =
filesMatching(query, _.endsWith(_))
def filesContaining(query: String) =
filesMatching(query, _.contains(_))
def filesRegex(query: String) =
filesMatching(query, _.matches(_))
}
2-b. クロージャ導入
filesMatching 第1引数の query は、第2引数のマッチング関数に渡されるだけなので、第2引数をクロージャにすることで省略できます。
object FileMatcherHOClosure {
private def filesHere = (new java.io.File(".")).listFiles
// ヘルパメソッドの定義からqueryが除かれている
// クエリ文字列は、matcherクロージャが(実行時に)文脈からキャプチャする
private def filesMatching(matcher: String => Boolean) = {
for(file <- filesHere; if matcher(file.getName))
yield file
}
// filesMatchingにクロージャを渡す
// name は束縛変数(bound variable), query は自由変数(free variable)
def filesEnding(query: String) =
filesMatching((name:String) => name.endsWith(query))
def filesContaining(query: String) =
filesMatching((name:String) => name.contains(query))
def filesRegex(query: String) =
filesMatching((name:String) => name.matches(query))
}
2-ab. プレースホルダー&クロージャ使用 (Listing 9.1)
2-a. と 2-b. をがっちゃんこすると Listing 9.1 のコードになります。
object FileMatcherHOClosurePlaceHolder {
private def filesHere = (new java.io.File(".")).listFiles
private def filesMatching(matcher: String => Boolean) = {
for(file <- filesHere; if matcher(file.getName))
yield file
}
def filesEnding(query: String) =
filesMatching(_.endsWith(query))
def filesContaining(query: String) =
filesMatching(_.contains(query))
def filesRegex(query: String) =
filesMatching(_.matches(query))
}
# しかしくどいなぁ。クロージャなんとなくわかってきた。
0 件のコメント:
コメントを投稿