【Scala】関数型初心者のカリーの勉強
カリー
この事らしい。
def curry[A,B,C](f: (A, B) => C): A => (B => C) = (a: A) => (b => f(a, b)) // curry: [A, B, C](f: (A, B) => C)A => (B => C)
異なる型パラメータA,B,Cに対してA,Bを引数に取り戻り値がCとなるような関数をAを引数にして戻り値をBを引数にしてCを戻り値にする関数
ってことね 😓
具体化
先ほどの関数curryに対し、代入できる関数を用意する。
def sum(a: Int, b: Short): Long = a + b // sum: (a: Int, b: Short)Long
このexpression成立するんだscala。
んで、
val c = curry(sum) // c: Int => (Short => Long) = $$Lambda$1131/1160112616@443a53df
これがカリー化らしい。 つまりaとbからcを産む関数から、aからbを引数にして戻りにcにする関数に変換したみたいな話。
不思議な感覚がしますね。
val c_sum = c(10) // c_sum: Short => Long = $$Lambda$1132/92962244@61b60600
10を引数にして、c_sum関数を引数にした変数に10を足してLongで返します。
scalaは func()()
みたいに高階関数を書けるのでワンライナーで関数をほどくと、
val cc_sum = c(10)(100) // cc_sum: Long = 110
うん、確かに sum(10, 100)
と c(10)(100)
は同じ結果になったようだ。
アンカリー
多分カリーの美しいとされる所は、関数レイヤー操作を単純な関数で表現しつつも、それが副作用なし[要出典]で可逆な所なんだろうと思う。
つまりuncurry(curry(sum))
で sum
に戻せる関数を定義できる。
def uncurry[A,B,C](f: A => (B => C)): (A, B) => C = (a, b) => f(a)(b) // uncurry: [A, B, C](f: A => (B => C))(A, B) => C
val ex_sum = uncurry(curry(sum)) // ex_sum: (Int, Short) => Long = $$Lambda$1141/570434649@75ac326f
val result = ex_sum(10, 100) // result: Long = 110
書いてみるとすっと分かるね。
感想
要は関数のレイヤーを一段あげさげするってことなんだろうな。 なんとなくわかった。