Scalaの関数オブジェクト

1 min read読了の目安(約1500字

Scalaでは関数リテラルが用意されていて、実行すると関数のオブジェクトが生成される。

scala> val plusOne = (x: Int) => x + 1
val plusOne: Int => Int = $Lambda$1055/0x00000008010ef840@75a226ea

scala> val result = plusOne(2)
val result: Int = 3

例えば引数が一つの関数リテラルは、Function1 traitを継承したオブジェクトを生成する。

下記のコードは、最初に出てきたリテラルと等価である。引数の数に合わせてFunction0〜Function22までのtraitが用意されている。

scala> val plusOne = new Function1[Int, Int] {
     |      def apply(x: Int): Int = x + 1
     |    }
val plusOne: Int => Int = <function1>

scala> val result = plusOne(2)
val result: Int = 3

特にFunction1はいくつかの興味深いメソッドを提供する。

例えばandThenメソッドで、関数の合成ができる。

scala> val plusOne = (x: Int) => x + 1
val plusOne: Int => Int = $Lambda$1106/0x00000008010ee840@515d615

scala> val double = (x: Int) => x * 2
val double: Int => Int = $Lambda$1107/0x0000000801119040@6d6d81c

scala> val plusThenDouble = plusOne andThen double
val plusThenDouble: Int => Int = scala.Function1$$Lambda$1111/0x000000080111b840@5b4880b3

scala> val result = plusThenDouble(2)
val result: Int = 6

curriedメソッドを使えば、関数はカリー化される…引数を一つだけ取る関数に変換される。

下記の例では、引数を二つ取り、足し算を行う関数を、引数を一つ取り、更に引数一つを与えると最初の引数の値と足し算を行う関数を返している。

scala> val plus = (x: Int, y: Int) => x + y
val plus: (Int, Int) => Int = $Lambda$1112/0x000000080111f840@40aaf656

scala> val cPlus = plus.curried
val cPlus: Int => (Int => Int) = scala.Function2$$Lambda$1113/0x000000080111e840@41c05747

scala> val appliedOneArg = cPlus(2)
val appliedOneArg: Int => Int = scala.Function2$$Lambda$1114/0x000000080111e040@119de68f

scala> val appliedTwoArg = appliedOneArg(3)
val appliedTwoArg: Int = 5