$shibayu36->blog;

株式会社はてなでエンジニアをしています。プログラミングや読書のことなどについて書いています。

Scalaの関数リテラルの学習メモ

Scalaスケーラブルプログラミングを読んでいて、関数リテラルについて気になったことがあったので、いろいろ試したことをメモしておく。

Scalaスケーラブルプログラミング第3版

Scalaスケーラブルプログラミング第3版

関数リテラルの基本形

基本形はこんな感じ。

val f = (a: Int, b: Int) => a + b
f(1,2)

省略記法

アンダースコアを使って省略できる。

val f = (_: Int) + (_: Int)
f(1,3)

このままだとアンダースコアに型を付けないといけないけど、変数側に型を明示しておくとアンダースコア側に型を書かなくても済む。これが利用されてfilter関数とかはアンダースコアに型が書かなくても良い。

val f: (Int, Int) => Int = _ + _
f(1,4)

関数の部分適用

関数の部分適応もアンダースコアを使って作れる。

val f2 = f(1, _: Int)
f2(2)

これ、記法覚えにくいなと思ったけど、よく考えると関数の省略形と同じと気づいたので難しくなかった。つまり以下に頭の中で変換すれば難しくない。

val f2 = (a: Int) => f(1, a)
f2(2)

これも変数側に型を書けばアンダースコア側に書かなくても良さそう。

val f2: (Int) => Int = f(1, _)

関数オブジェクト化

defで書かれた関数を関数オブジェクト化するのにもアンダースコアを使う。これはC言語の関数ポインタを取得するのとか、Perlの&で関数リファレンスを取り出すのと同じと考えたら分かりやすかった。

def sum(a: Int, b: Int) = a + b
val f = sum _

推論できないときにだけ明示的にアンダースコアを使うということなので、推論が必要なければアンダースコアも省略できる。

val f: (Int, Int) => Int = sum

推論が必要なければアンダースコアが省略できるので、以下のようにListのforeachにdefで定義された関数を渡す時もアンダースコアを使わなくて良いと理解した。

List(1,2,3).foreach(println)