See the Elephant

1992生まれのプログラマが書くエンジニアブログ

scalaで高階関数を学ぶ

scalaで関数を学ぶ

いつものドワンゴscala講座を読む

関数 · Scala研修テキスト

今日は 関数

関数

scalaでは関数もオブジェクト。

メソッドと関数は異なるらしい。

本来はdefで始まる構文で定義されたものだけがメソッド。
関数オブジェクトを関数と呼ぶ。
便宜上、メソッドも関数と呼ぶことがある。

こんな感じ。

scalaでは無名関数の宣言をカジュアルに行える。以下みたいに

// オブジェクト名: 引数型 => 戻り値型 = 引数名 => 処理
val f: String => Int = argValue => argValue.toInt * 2

と書けば無名関数の宣言と同時に変数に代入できる。

高階関数

関数を引数に取ったり関数を返すメソッドや関数のことを高階関数と呼ぶ。

以下の例みたいに、外から値と関数を渡して実行できる。

// 宣言
scala> def double(n: Int, f: Int => Int): Int = {
     |   f(f(n))
     | }
double: (n: Int, f: Int => Int)Int

// 実行
scala> double(1, m => m * 2)
res4: Int = 4

この例はintを返しているけど、関数を返すこともできるっぽい。

全然読めなかった高階関数の宣言

以下の関数はドキュメントからそのまま持ってきたものである。

scala> import scala.io.Source
import scala.io.Source

scala> def withFile[A](filename: String)(f: Source => A): A = {
     |   val s = Source.fromFile(filename)
     |   try {
     |     f(s)
     |   } finally {
     |     s.close()
     |   }
     | }
withFile: [A](filename: String)(f: scala.io.Source => A)A

引数が (引数1)(引数2) となっている。

これまで書いてきた、C, PHP, RubyではこのSyntaxを見たことがなかったので戸惑った。

qiita.com

これを読む感じだとカリー化っぽいね。

ということでカリー化と同時実行の両方をやってみた。

ioで使うファイルはこれ

$ cat hoge
hogepiyohuga

さて、色々試してみよう

scala> def withFile[A](filename: String)(f: Source => A): A = {
     |   val s = Source.fromFile(filename)
     |   try {
     |     f(s)
     |   } finally {
     |     s.close()
     |   }
     | }

// -- カリー化 --
// fにファイル名だけ固定した関数を代入

scala> val f = withFile[String]("hoge")_
f: (scala.io.Source => String) => String = $$Lambda$917/0x000000080061c840@5896cb9c

// 関数内で使われる関数を宣言

scala> val ff: Source => String = s => s.getLines.mkString
ff: scala.io.Source => String = $$Lambda$920/0x0000000800629040@1de30c31

// hogeの中身を読み取って ffが実行される
scala> f(ff)
res3: String = hogepiyohuga

// -- 同時実行 --
// filenameと実行関数を同時に渡す

scala> val f = withFile[String]("hoge")(ff)
f: String = hogepiyohuga

そこそこ理解できた。今日はこれで