From: Takaaki Tateishi Date: 2000-11-19T12:06:19+09:00 Subject: [ruby-dev:11599] Re: accumulator, Enumerable#{foldr,foldl} 立石です. At Sun, 19 Nov 2000 11:27:39 +0900, 立石 wrote: > あるいは,Enumerable#{foldl,foldr}のようなものが標準で欲しいので > すがユーザが定義するべきでしょうか? 個人的には結構使えそうな気が > > [a1,a2,...,an].foldl(a0){|x,y| f(x,y)} > => f(f(...(f(a0,a1),a2)...)) > > [a1,a2,...,an].foldr(a0){|x,y| f(x,y)} > => f(a1,f(a2,f(...,f(an,a0)))) 一応,Enumerableの方は実装してみました が,こんな感じでいいのでしょうか? -- Takaaki Tateishi http://kt-www.jaist.ac.jp:8000/~ttate/ Index: enum.c =================================================================== RCS file: /home/cvs/ruby/enum.c,v retrieving revision 1.11 diff -c -r1.11 enum.c *** enum.c 2000/05/24 04:33:54 1.11 --- enum.c 2000/11/19 03:02:47 *************** *** 322,327 **** --- 322,371 ---- return Qnil; } + static VALUE + foldl_i(val, memo) + VALUE val; + NODE *memo; + { + memo->u3.value = rb_yield(rb_assoc_new(memo->u3.value, val)); + return Qnil; + } + + static VALUE + enum_foldl(obj, init) + VALUE obj, init; + { + NODE *memo = rb_node_newnode(NODE_MEMO, 0, 0, 0); + + memo->u3.value = init; + rb_iterate(rb_each, obj, foldl_i, (VALUE)memo); + rb_gc_force_recycle((VALUE)memo); + return memo->u3.value; + }; + + static VALUE + foldr_i(val, memo) + VALUE val; + NODE *memo; + { + memo->u3.value = rb_yield(rb_assoc_new(val, memo->u3.value)); + return Qnil; + } + + static VALUE + enum_foldr(obj, init) + VALUE obj, init; + { + NODE *memo = rb_node_newnode(NODE_MEMO, 0, 0, 0); + ID id_reverse = rb_intern("reverse"); + + memo->u3.value = init; + rb_iterate(rb_each, rb_funcall(obj,id_reverse,0,0), foldr_i, (VALUE)memo); + rb_gc_force_recycle((VALUE)memo); + return memo->u3.value; + }; + + void Init_Enumerable() { *************** *** 344,349 **** --- 388,395 ---- rb_define_method(rb_mEnumerable,"member?", enum_member, 1); rb_define_method(rb_mEnumerable,"include?", enum_member, 1); rb_define_method(rb_mEnumerable,"each_with_index", enum_each_with_index, 0); + rb_define_method(rb_mEnumerable,"foldl", enum_foldl, 1); + rb_define_method(rb_mEnumerable,"foldr", enum_foldr, 1); id_eqq = rb_intern("==="); id_each = rb_intern("each");