Home About Contact
Kotlin

Kotlin 関数の部分適用(またはカリー化)

ときどき 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)

まあ、これで目的は果たせるのかな。