【Scala】Javaを使っている僕が感動したScalaの機能 カリー化 部分適用

Javaには無くて、Scalaにはある素晴らしい機能の一つに関数を変数に入れて使えるが、
これが予想以上に便利なんだ。

僕は関数を変数に入れられるというから、「Javaのクラスの小さいものだろ?」くらいに思っていたが
Javaより手軽に使えるし、何よりもJava特有の冗長な書き方も制限も少なくとても便利だ。

部分適用

部分適用というのは関数の引数を一部適用して、変数に代入するやり方だ。
func(x,y)とか2つ引数が必要な関数があったとする。
しかし、自分が書いているクラスでは、一方の引数が固定だったらどうだろう。

Javaならばひとつの手として一個一個、同じ値を入れていく。
マジックナンバーを入れるわけにはいかないので、定数をフィールドに宣言して引数にいつも同じ定数を入れる。

もしくはそのメソッドを持っているクラスを継承し、引数を一つだけとるメソッドを定義して内部で固定の引数と共にスーパークラスのメソッドへ処理を投げる。

または自分の書いているクラス内に引数を一つだけとるプライベートメソッドを定義して、引数を2つ必要なメソッドに処理を投げる。いわゆる移譲ってやつだ。

どれも面倒くさいな。一番最初は冗長になるし、いつも固定値が入るということをアピールするには主張が小さい気がする。
2つ目はクラス作らなくちゃいけない。
3つ目は一番労力が少ないけれど…それでも新たにメソッドを定義しなくちゃいけない。

Scalaならば変数に関数を代入するだけ。

以下にサンプルを書いてみた

object Test {

  def main(args: Array[String]): Unit = {

    //引数を2つ取るメソッドを定義した。
    def plus(x : Int , y : Int):Unit = println(x + " + " + y + " = " + (x+y))

    // 普通にメソッドを呼ぶならばこうだ
    plus(3,2)

    /*
     *  しかしxは常に10が入るクラスがあったとして、
     *  何度も使用する場合はこうだ
     */
    val tenplus = plus(x = 10 , _:Int)

    // これで引数を一つ取るだけの関数が出来上がった。
    tenplus(5)
    tenplus(45)
  }
}

結果はこんな感じ

3 + 2 = 5
10 + 5 = 15
10 + 45 = 55

カリー化

似たような機能にカリー化ってのがある。

これも部分適用と同じような機能なんだけれども、内部的には違うらしい。
複数の引数のうち、最初の引数だけを渡せば、残りの引数を使って処理をする関数を返す関数というのがカリー化。

func(x , y) という2つの引数が必要な関数があったとして、xだけを指定するとその戻り値としてyを引数に取って処理をする関数が返ってくるという事だ。

サンプルで示します。

object Test2 {

  def main(args: Array[String]): Unit = {

    //2つの引数が必要な関数だけれども、カリー化されている。
    def curryplus(x:Int)(y:Int) : Int = x+y

    //xに数値を渡して、yとzが必要な関数を取得します。
    val cp = curryplus(10)_
    //cpは引数を一つ取って数値を返す。
    println(cp(32))

    /**
     * xを指定するとyとzを引数にとって計算をする関数を返す関数
     */
    def curryplus2(x:Int)(y:Int,z:Int) : Int = x+y+z

    val cp2 = curryplus2(20)_
    //cp2は数値を2つ取って結果を返す。
    println(cp2(10,20))

    /**
     * xを渡すと「yを渡すと「zを渡すと処理をする関数」を返す関数」を返す関数
     */
    def curryplus3(x:Int)(y:Int)(z:Int) : Int = x+y+z

    val cp3 = curryplus3(100)_
    //cp3は関数を返す関数
    val cp4 = cp3(230)
    //cp4は数値を一つ取って結果を返している。
    println(cp4(500))

    //メソッドチェーンとして実行することも可能
    println(curryplus3(321)(3244)(4321))

  }

}

実行結果は以下の通り

42
50
830
7886

部分適用と似ているけれど、おそらく僕が思うところによると
カリー化されたメソッドというのは、引数を取って関数を変数として使えというアピールをするために使うんだろうな。

部分適用というのは自分で元からあるメソッドを使いやすいように活用するためで、
カリー化は今後使う人に最初の引数を渡しておけば便利な関数が使えるので使ってくださいという主張をするためなんだろう。

ものすごい便利だ。
Scalaには流行って欲しい。

スポンサードリンク

関連コンテンツ