ゆうなんとかさんの雑記帳的な。

Twitterで踊ったり音ゲーしたりしてるあの名前がよくわからない人が書いてるらしいよ。

カリー化やってみた

カリー化とは

2変数の関数 F(x, y) = aという関数があったとき、これを高階関数f(x)がg(y) = aとなる関数を返すようにすることです。
関数が3変数以上のときも同じように、もとの第1引数を引数に取り、上のような条件で残りの引数を引き受ける関数を返すようにしていき、最終的に1引数の関数の呼び出し連鎖にしてしまいます。
F(x_1,x_2,x_3, ... ,x_n) = a

f_1(x_1) = G,  G(x_2, x_3,...,x_n) = a



f_1(x_1) = f_2, f_2(x_2) = f_3, ..., f_{n-1}(x_{n_1}) = f_n, f_n(x_n) = a
まずは2つの引数を取り、その和を求めるint add(int a,int b)という簡単な関数を定義します。Cで普通に書けばこうですね。

int add(int a,int b) { return a + b; }

ではこれをJavaScriptでカリー化してみましょう。

function add(a) {
  return function(b) { return a + b; }
}

ちなみにRubyの場合はProc#curryでカリー化してくれます。PythonJavaScriptなどが間違った意味で「curry」というキーワードを使っている*1中、Rubyはちゃんとカリー化します。

add = Proc.new {|x,y| x + y }.curry # Proc.new {|x| Proc.new{|y| x + y } } と同じ感じになる

Haskellだと意識しなくてもこうなってます。いやいや、多変数の関数作れるよね?実はそれ糖衣構文らしいですよ?

add :: Int -> Int -> Int -- ←このへんを見てピンときた方もいるのでは
add a b = a + b     -- これと
add a = \b -> a + b -- これはおんなじ

これを元に、引数を定数に束縛することで、引数をカスタマイズした関数を使いまわすこともできます。

function add(a) {
  return function(b) { return a + b; }
}
add2 = add(2);
add2(3); // 5
add2(4); // 6

JavaScriptだといまいち美味しくないですが、Haskellだとこういう挙動を前提にプログラミングできるのでかなりおいしいです。

*1:部分適用と間違えているらしい