From: Yusuke ENDOH Date: 2008-02-09T20:40:19+09:00 Subject: [ruby-dev:33676] Suggestion: Proc#curry 遠藤と申します。 http://subtech.g.hatena.ne.jp/cho45/20071119/1195420784 で提案されている Proc#curry を組み込むのはどうでしょうか。 proc {|x, y, z| x + y + z }.curry が proc {|x| proc {|y| proc {|z| x + y + z } } } と同じ意味になります。 ski コンビネータを書くときなどに、ささやかな幸せが得られます。 s = proc {|f, g, x| f[x][g[x]] }.curry k = proc {|x, y| x }.curry 逆に、Proc#curry の存在が害になることはないと思います。 以下はたたき台です。 Index: proc.c =================================================================== --- proc.c (revision 15417) +++ proc.c (working copy) @@ -1608,7 +1608,60 @@ return bindval; } +static VALUE curry(VALUE dummy, VALUE args, int argc, VALUE *argv); + +static VALUE +make_curry_proc(VALUE proc, VALUE passed, VALUE arity) +{ + VALUE args = rb_ary_new2(3); + RARRAY_PTR(args)[0] = proc; + RARRAY_PTR(args)[1] = passed; + RARRAY_PTR(args)[2] = arity; + rb_ary_freeze(args); + rb_ary_freeze(passed); + return rb_proc_new(curry, args); +} + +static VALUE +curry(VALUE dummy, VALUE args, int argc, VALUE *argv) +{ + int i; + VALUE proc, passed, arity; + proc = RARRAY_PTR(args)[0]; + passed = RARRAY_PTR(args)[1]; + arity = RARRAY_PTR(args)[2]; + + passed = rb_ary_plus(passed, rb_ary_new4(argc, argv)); + if(RARRAY_LEN(passed) < FIX2INT(arity)) { + return make_curry_proc(proc, passed, arity); + } + return rb_proc_call(proc, passed); +} + /* + * call-seq: + * prc.curry => a_proc + * + * Returns a curried proc. + * + * x = proc {|a, b, c| a + b + c } + * p x[1, 2, 3] #=> 6 + * x = x.curry + * p x[1][2][3] #=> 6 + */ +static VALUE +proc_curry(VALUE self) +{ + VALUE arity = proc_arity(self); + + if(FIX2INT(arity) < 0) { + arity = INT2FIX(-FIX2INT(arity) - 1); + } + + return make_curry_proc(self, rb_ary_new(), arity); +} + +/* * Proc objects are blocks of code that have been bound to * a set of local variables. Once bound, the code may be called in * different contexts and still access those variables. @@ -1646,6 +1699,7 @@ rb_define_method(rb_cProc, "to_s", proc_to_s, 0); rb_define_method(rb_cProc, "lambda?", proc_lambda_p, 0); rb_define_method(rb_cProc, "binding", proc_binding, 0); + rb_define_method(rb_cProc, "curry", proc_curry, 0); /* Exceptions */ rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError); -- Yusuke ENDOH