curry化と部分適用の違いについて
今日は, rubyでcurry
を勉強していた.
ruby 2.4.0の日本語リファレンスMethod#curry
によるとこう書かれている.
self を元にカリー化した Proc を返します。カリー化した Proc はいくつかの引数をとります。十分な数の引数が与えられると、元の Proc に引数を渡して実行し、結果を返します。引数 の個数が足りないときは、部分適用したカリー化 Proc を返します
か, カリー化ってなんだ….?
wikiによるとカリー化とはこういう意味らしい.
カリー化 (currying, カリー化された=curried) とは、複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること(あるいはその関数のこと)である。
ふーん. なるほど.
ということは,
div = lambda {|x, y| x.to_f/y.to_f}.curry # ラムダ式をカリー化 div1 = add.(1) # xを1に束縛, div1.(4) # yを4に束縛, このタイミングでprocが実行される #=> 5
これで俺もカレー職人や!!!
と思っていたらこれはどうやら部分適用と呼ぶらしい.
カリー化と部分適用の違い
curry化と部分適用を混同してる人が多いと書かれたブログを見つけた. 部分適用をカリー化と呼ばないで - kmizuの日記
いまいちピンと来なかったので, 調べてみると こんな書き込みを見つけた(Shingo Omura @everpeace)
x,y,z -> V をx -> (y->(z->V)) に変換するのがカリー化。x,y,z-> Vのyに値を束縛して結果的にx,z->Vという関数になるのが部分適用。どこが同じなんだろうか。
なるほど. 階層化することが大切なんだね. でもいまいちピンと来ていない.
見落としていたけど, wikiの下の方にこんなことが書いてあった.
カリー化は部分適用と混同されやすい。
部分適用とは、
複数引数ある関数の引数の一部だけに実引数を適用する操作
のことで、div->inv
を導出する操作を指す。
一方、カリー化は
div->cdiv
を導出する操作であり、引数への値の適用までは行わない.
div = lambda {|x, y| x.to_f/y.to_f} cdiv = lambda {|x| lambda{|y| div.(x,y)}} inv = cdiv.(1) p inv.(2) #=> 0.5
つまり, 値を入れた時点で「部分適用」になるんですね.
wikiによると, カリー化は以下のように表現されていた.
...Haskellでは関数は常に一つの引数のみを取り、複数の引数を取る関数とは、単にネストされた複数の一引数関数の糖衣構文(syntax suger)にすぎない
なるほど.
今読み返すと@everpeace
さんの表現がとてもわかり易い.
x,y,z -> V をx -> (y->(z->V)) に変換するのがカリー化。x,y,z-> Vのyに値を束縛して結果的にx,z->Vという関数になるのが部分適用。どこが同じなんだろうか。
調べてみて, 僕の中での「カリー化」の理解は, 以下のような感じでまとまった.
カリー化 = 複数の引数を取る関数を, 常に1つの引数を取る関数が多層化された関数に変換すること