nがひとつ多い。

えぬなおの技術的なことを書いていくとこ。

【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で返します。 scalafunc()() みたいに高階関数を書けるのでワンライナーで関数をほどくと、

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

書いてみるとすっと分かるね。

感想

要は関数のレイヤーを一段あげさげするってことなんだろうな。 なんとなくわかった。