情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

F#入門(8)関数の部分適用

カリー化(currying)とは、n個の引数を取る1つの関数を、1つの引数を取るn個の関数の連鎖に変換する操作のことです。

数式を使って書くと、関数

f:(X1×X2×……Xn)→Y

が与えられた時、カリー化関数(curried function)

curry(f):X1→(X2→(……→Xn……))

を得る操作をカリー化と言います。この場合、カリー化関数curry(f)は1つの引数x1∈X1を取り関数X2→(X3→(……→Xn……))を返す関数です。返された関数X2→(X3→(……→Xn……))は1つの引数x2∈X2を取り関数X3→(X4→(……→Xn……))を返す関数です。このような連鎖がn回続くことになります。

F#の関数は通常自動的にカリー化されます。

例えば、2つの引数を取ってその和を返す関数は次のようになります。

let summation1 a b = a + b

これは記法上2個の引数を取る関数に見えますが、F#では自動的にカリー化されるので、以下のような関数を返す関数と同じになります。

let summation2 a =

    fun b -> a + b

実際、2つの関数をF#インタープリタで定義してみると全く同じ結果が返ってきます。

また、これは括弧がない点を除いて、上記の数式によるカリー化関数の表現とも同じであることが分かります。

関数summation1で第1引数だけを渡せば、第1引数が部分適用された(partially applied)関数が返されます。

let x = 4

let y1 = 6

let y2 = 8

let summation1 a b = a + b

let summation2 = summation1 x

let result1 = summation2 y1

let result2 = summation2 y2

printfn "%d + %d = %d" x y1 result1

printfn "%d + %d = %d" x y2 result2

F#の関数は全て自動的にカリー化されますが、場合によってはカリー化を抑止したいことがあります。つまり、関数を複数個の引数を取る1つの関数として定義したい場合があります。

その場合は、引数全体を括弧で囲みそれぞれの引数をカンマで区切ります。そうすると自動的にカリー化されることはありません。

例えば、先の関数summation1を自動的にカリー化させないようにするには、次のようにします。

let summation (a, b) = a + b

関数の定義後にF#インタープリタによって返された結果が先程とは異なっており、int * int -> intと2つのint型の引数を取ってint型の値を返す関数が定義されたことが分かります。

この関数を呼び出すときは、2つの引数を同時に渡さなければならないのは勿論ですが、関数を定義した時と同じように引数全体を括弧で囲みそれぞれの引数をカンマで区切らなければなりません。さもないと、エラーが発生します。具体的には以下のように書きます。

printfn "result = %d" (summation (1, 2))

引数全体を括弧で囲みそれぞれの引数をカンマで区切らないと、summation 1は関数ではなく、引数を適用できないと怒られます。

1つしか引数を渡さないと、型が違うと怒られます。

pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-F#