読み解き PiS3: Higher Order Functions を使って複数ファイルの一括処理を行う

9.4 WRITING NEW CONTROL STRUCTURES を読んでいて、複数ファイルに対して「ファイルを開いて特定の処理を行う」ことができるはずと思って実装した。Scala でメソッドをメソッドの引数に取るのは HOF(Higher Order Functions) というらしい。 C でいう関数ポインタがさらに高度になったようなイメージを持っている。

「ファイル名を受け取って、開く」までは共通だけれども、開いたファイルに対して実行したいことが異なる場合は 3 番目のメソッドだけ入れ替えればいいので柔軟性に富む。左から右に処理が書かれているのもわかりやすいかもしれない。⊂( ・∀・) 彡

$ cat /tmp/fruits.txt
apple
banana

$ cat /tmp/animals.txt
cat
dog
@ import scala.io.Source
import scala.io.Source

@ val files = List("/tmp/fruits.txt", "/tmp/animals.txt")
files: List[String] = List("/tmp/fruits.txt", "/tmp/animals.txt")

@ val getFileContents = (path: String) => Source.fromFile(path).getLines
getFileContents: String => Iterator[String] = ammonite.$sess.cmd2$$$Lambda$2031/1972193961@11a67420

@ def crunchFiles(paths: List[String], f1: String => Iterator[String], f2: String => Unit): Unit = paths.foreach { path => f1(path).foreach { line => f2(line) } }
defined function crunchFiles

@ def printWithIndent(line: String) = println(s"    $line")
defined function printWithIndent

@ crunchFiles(files, getFileContents, printWithIndent)
    apple
    banana
    cat
    dog

@ def printIfWordContainsCharA(line: String) = if (line.contains("a")) println(line)
defined function printIfWordContainsCharA

@ crunchFiles(files, getFileContents, printIfWordContainsCharA)
apple
banana
cat

@ import java.io.File
import java.io.File

@ new File("/tmp").listFiles.filter(_.toString.endsWith("txt"))
res23: Array[File] = Array(/tmp/animals.txt, /tmp/fruits.txt)

@ def crunchFiles(files: Iterator[String], f1: String => Iterator[String], f2: String => Unit): Unit = files.foreach { path => f1(path).foreach { line => f2(line) } }
defined function crunchFiles

@ val listTextFilesUnderDirectory = (dir: String) => new File(dir).listFiles.filter(_.toString.endsWith("txt")).toList.map(_.toString).toIterator
listTextFilesUnderDirectory: String => Iterator[String] = ammonite.$sess.cmd41$$$Lambda$2447/934433293@4f559d04

@ crunchFiles(listTextFilesUnderDirectory("/tmp"), getFileContents, printIfWordContainsCharA)
cat
apple
banana

@
def crunchFiles(dir: String, f0: String => Iterator[String], f1: String => Iterator[String], f2: String => Unit): Unit = f0(dir).foreach { path => f1(path).foreach { line => f2(line) } }
defined function crunchFiles

@ crunchFiles("/tmp", listTextFilesUnderDirectory, getFileContents, printIfWordContainsCharA)
cat
apple
banana