カリー化とは
複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること。
http://wiki.onakasuita.org/pukiwiki/?%E3%82%AB%E3%83%AA%E3%83%BC%E5%8C%96
http://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%AA%E3%83%BC%E5%8C%96
など参考
最近は「関数が第一級のオブジェクト」、要は「手続きの固まり」を文字列や数字のようにモノ扱いできる、RubyやJavaScriptのような言語が普及しているが、そういう言語では「カリー化」の手法が使える。
例えばRubyで、x個の、yから始まる数の総和を求めるorigという関数を考える。
1 2 3 4 5 6 7 | def orig(x, y) ret = 0 for i in y..(x + y - 1) do ret += i end return ret end |
このorig(x, y)を元に、「3個」「4個」「5個」の、yから始まる数の総和を求める関数を作りたい。下の如し。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | def curried_orig(x) lambda do |y| orig(x, y) end end sum3 = curried_orig(3) #=> #<Proc:0x0000002a955cf098> sum4 = curried_orig(4) #=> #<Proc:0x0000002a955cf098> sum5 = curried_orig(5) #=> #<Proc:0x0000002a955cf098> sum3[10] #=> 10+11+12 = 33 sum4[10] #=> 10+11+12+13 = 46 sum5[10] #=> 10+11+12+13+14 = 60 |
sum3やsum4に束縛されるのは、実際にはメソッドというよりProcオブジェクトなので、()ではなく[]で呼び出す。
Ruby1.9.1からは「Proc#curry」が導入され、よりすっきり書ける。
1 2 3 4 5 6 7 8 9 10 | sum_x = lambda {|x, y| ret = 0 for i in x...(x + y) do ret += i end return ret } sum3 = sum_x.curry[3] sum3[10] #=> 10+11+12 = 33 |
数学的な概念は良く分かっていないけど。
http://www.nslabs.jp/closure.rhtml
「カリー化」とは (A, B) -> C という関数をA -> (B -> C) という関数に変換することです。
http://www.khelll.com/blog/ruby/ruby-currying/
Check this function f which takes 3 params x,y,z
f(x,y,z) = 4*x+3*y+2*z
Currying means that we can rewrite the function as a composition of 3 functions(a function for each param):
f(x)(y)(z) = 2*z+(3*y+(4*x))
http://www.ruby-forum.com/topic/142699#633354
It’s not difficult at all,
1 proc {|x, y, z| x + y + z }.curryreturns the proc object equivalent to
1 proc {|x| proc {|y| proc {|z| x + y + z } } }
実際利用する時に「関数の部分適用」と「カリー化」を区別する意味ってあまり無いかもしれないんだけど。「Proc#curry」はこういう意味ですよ、というのは認識したほうがいいのかも。
その他のカリー化の使い方例 参考:「Fun with Procs in Ruby 1.9」
http://pragdave.blogs.pragprog.com/pragdave/2008/09/fun-with-procs.html
* * *
※: 個人的に普段はこう書いてしまい俺気持ちが悪い。
1 2 3 | def orig(x, y) (0...x).to_a.map{|v| y + v}.inject{|d, s| d += s} end |