Squirrelでカリー化
カリー化のオレオレ定義がまたひとつ / javascript で遊ぶラムダ式、クロージャ、カリー化 by rti 7743 on Prezi prezi.com/9brwewgcxtr2/j…
— kxbmapさん (@kxbmap) 9月 27, 2012
これの資料自体は結構古かったですね。部分適用の特殊な場合をカリー化としている例は今まで見たことなかったのでつい反射的に。カリー化そのものについては以下のリンクを参照してください。丸投げです。
カリー化の誤用についてはこのマサカリをどぞー > togetter.com/li/183700 d.hatena.ne.jp/kazu-yamamoto/… / “javascript で遊ぶラムダ式、クロージャ、カリー化 by rti 7743 on Pr…” htn.to/a5yGTU
— 這い寄る債務者ゆるよろ(旧支配者)さん (@yuroyoro) 9月 27, 2012
ではSquirrel 2.xで関数をカリー化する関数を書いてみます。
function curry2(f) { return function (a) : (f) { return function (b) : (f, a) { return f(a, b); }} } function curry3(f) { return function (a) : (f) { return function (b) : (f, a) { return function (c) : (f, a, b) { return f(a, b, c); }}} } function curry4(f) { return function (a) : (f) { return function (b) : (f, a) { return function (c) : (f, a, b) { return function (d) : (f, a, b, c) { return f(a, b, c, d); }}}} }
はい。*1
関数fの仮引数の数を判別する手段がないので必要な分だけベタ書きでございます。可変長引数もあるししょうがない(?)です。
Squirrel3やJavaScriptと違って、外側のスコープのローカル変数の値を使うには関数定義時に明示的に渡しておく必要があります。
見た目愉快ですね。
curry2
には引数を2つ取る関数を渡すことができます。
function add(a, b) { return a + b; } curried_add <- curry2(add); local r0 = curried_add(2)(3); // r0 = 5 // 部分適用 add1 <- curried_add(1); local r1 = add1(5); // r1 = 6
もしくは、その数の引数を取ることのできる可変長引数を取る関数をカリー化(?)することもできます。
// 1つ以上の引数を取る関数を function product(a, ...) { local r = a; for (local i = 0; i < vargc; ++i) { r *= vargv[i]; } return r; } // 引数を3つ取る関数としてカリー化 curried_product <- curry3(product); local r2 = curried_product(2)(3)(4); // r2 = 24
この時、curried_product
の引数の数は固定化されています。
元の関数から変わってしまうのでカリー化と言えるのかは分かりません。
curried_product(2)(3)(4)(5); // => Error! 24(integer)に対するcall
また、カリー化された関数の引数の順番を入れ替えるflip
関数を以下のように定義できます。
function flip(f) { return function (a) : (f) { return function (b) : (f, a) { return f(b)(a); }} }
function join(a, b, c) { return a + "," + b + "," + c; } curried_join <- curry3(join); local r3 = curried_join(1)(2)(3); // r3 = "1,2,3" flipped_join <- flip(curried_join); local r4 = flipped_join(1)(2)(3); // r4 = "2,1,3"
Squirrelでカリー化とかして何が嬉しいのか、というのはまた次に。