『カリー化』(Currying)

カリー化の定義

複数の引数をとる関数を、以下のように変化させることをカリー化と呼ぶ。
・引数 :「『もとの関数』の第1引数のみ」
・戻り値:以下の様に定義される「関数」
・『もとの関数』の第2引数以降を引数として受け取る
・『もとの関数』と同じ戻り値を返す
例えば、CoffeeScriptで書くと以下のようになる。

sum = (a, b, c) -> a + b + c
console.log sum(1,2,3) # ... 6

をカリー化すると、

currySum = 
	return (a) ->
		return (b) ->
			return (c) ->
				a + b + c

# スマートに書くなら、以下のようになる (CoffeeScriptすげー)
# currySum = (a) ->  (b) ->  (c) ->  a + b + c

console.log currySum(1)(2)(3) # ... 6

となる。

カリー化の使いどころ

さて、カリー化ができるようになって何がうれしいか。
それは、1引数の関数を受け取る高階関数に、2引数の関数を渡せるようになることだ。

http://yuroyoro.hatenablog.com/entry/2012/08/10/232443
ただし、
・通常の方法で定義された関数は、すべてカリー化されている
・関数適用の構文がシンプル
高階関数を多用する API が用意されている
といった条件が満たされている言語(haskellとか)でないと、カリー化を利用するための手間がカリー化を利用することによって得られるメリットを上回ってしまう。

curryDiv = (a) ->  (b) -> a / b

array = [5, 3, 6, 2]

# 10 / n の計算をする
array.map currySum(10) # ... [2, 0.666, 0.333, 1]

またhaskellとかには関数のどの引数を残すかを簡単に変えられる機能があるので、それを使えばどの引数を固定化するかが決められる。

# n / 2 の計算をする ( flipは実際はjavascriptに無いが、カリー化関数の引数順を入れ替えると考える
array.map currySum.flip(2) # ... [2.5, 1.5, 3, 1]

あと、引数が1つになるので合成関数が作れるようにになる。

func1(func2(func3(n)))
   ↓
(func1 . func2 . func3)(n);  // "."を合成関数演算子として考える(実際はjavascriptに合成関数演算子なんて無いが)