ときどき Haskell のように気軽に部分適用したくなることがある。 例のための例になるが、ARGB のカラーを生成する場合を考えてみる。
こんな Color クラスがあるとする。
data class Color(val a: Int, val r: Int, val g: Int, val b: Int)
これを使って、透明でない白と黒、半透明な白と黒のインスタンスをそれぞれ生成することを考える。 Color インスタンスをつくるには Color(255, 0,0,0) のようにすればいいのだが、 このように、直接生成してしまうと、関数の部分適用を使うことがないので、 ここでは、関数 toColor を経由して生成することとする。
val toColor: (Int, Int, Int, Int)->Color = { a,r,g,b->
Color(a,r,g,b)
}
Colorインスタンを実際に生成するコード。
val black1 = toColor(255, 0,0,0)
val white1 = toColor(255, 255,255,255)
val black2 = toColor(64, 0,0,0)
val white2 = toColor(64, 255,255,255)
このようなコードを書いた場合に、部分適用できれば楽なのに・・・と思う、このように。
val baseColor1 = toColor(255)
val black1 = baseColor1(0,0,0)
val white1 = baseColor1(255,255,255)
val baseColor2 = toColor(64)
val black2 = baseColor2(0,0,0)
val white2 = baseColor2(255,255,255)
Haskell だとこれで動いてくれる気がする(たぶん)。 Kotlin は自動ではカリー化してくれないので、自分でカリー化して部分適用できるようにしなければならない。 つまり・・・ 関数 toBaseColor を次のように定義。
val toBaseColor: (Int)->(Int, Int, Int)->Color = { a->
val f: (Int, Int, Int)->Color = { r,g,b->
Color(a,r,g,b)
}
f
}
このように冗長に型を書かなければ、次のようになる。
val toBaseColor: (Int)->(Int, Int, Int)->Color = { a->
{ r,g,b->
Color(a,r,g,b)
}
}
これで透明指定の数値だけを部分適用できるようになったので、目的は果たせる。
だったら、もう最初から全部部分適用できるように toColor を定義しておけばいいんじゃないの?
val toColor: (Int)->(Int)->(Int)->(Int)->Color = { a->
{ r->
{ g->
{ b->
Color(a,r,g,b) }}}}
これを使って Color インスタンスをつくる場合は次のように記述することになる。
val black1 = toColor(255)(0)(0)(0)
これなら不透明な色 baseColor1 をつくり、それから不透明な黒と白をつくるには:
val baseColor1 = toColor(255)
val black1 = baseColor1(0)(0)(0)
val white1 = baseColor1(255)(255)(255)
このようになる。
半透明の色をつくってから、白と黒を生成。
val baseColor2 = toColor(64)
val black2 = baseColor2(0)(0)(0)
val white2 = baseColor2(255)(255)(255)
まあ、これで目的は果たせるのかな。