diff --git a/enumerator.c b/enumerator.c
index 2563de5..9d1582f 100644
--- a/enumerator.c
+++ b/enumerator.c
@@ -119,6 +119,8 @@ struct enumerator {
     VALUE lookahead;
     VALUE feedvalue;
     VALUE stop_exc;
+    VALUE lazy;
+    VALUE procs;
 };
 
 static VALUE rb_cGenerator, rb_cYielder;
@@ -134,6 +136,8 @@ struct yielder {
 static VALUE generator_allocate(VALUE klass);
 static VALUE generator_init(VALUE obj, VALUE proc);
 
+static VALUE process_element(struct enumerator *e, VALUE result);
+
 /*
  * Enumerator
  */
@@ -1175,497 +1179,622 @@ generator_each(int argc, VALUE *argv, VALUE obj)
 }
 
 /* Lazy Enumerator methods */
+
+struct proc_entry {
+    VALUE proc;
+    VALUE type;
+};
+
+enum proc_entry_type {
+    T_PROC_MAP = 0,
+    T_PROC_SELECT = 1
+};
+
 static VALUE
-lazy_init_iterator(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    VALUE result;
-    if (argc == 1) {
-	VALUE args[2];
-	args[0] = m;
-	args[1] = val;
-	result = rb_yield_values2(2, args);
+process_element(struct enumerator *e, VALUE result)
+{
+    struct proc_entry *entry;
+    VALUE move_next = Qtrue;
+    VALUE *procs = RARRAY_PTR(e->procs);
+    long procs_number = RARRAY_LENINT(e->procs);
+    long i = 0;
+
+    for (i = 0; i < procs_number; i++) {
+        Data_Get_Struct(procs[i], struct proc_entry, entry);
+        switch ((enum proc_entry_type) entry->type) {
+            case T_PROC_MAP:
+                result = rb_funcall(entry->proc, rb_intern("call"), 1, result);
+                break;
+            case T_PROC_SELECT:
+                if (RTEST(move_next)) {
+                    move_next = rb_funcall(entry->proc, rb_intern("call"), 1, result);
+                }
+                break;
+        }
     }
-    else {
-	VALUE args;
-	int len = rb_long2int((long)argc + 1);
 
-	args = rb_ary_tmp_new(len);
-	rb_ary_push(args, m);
-	if (argc > 0) {
-	    rb_ary_cat(args, argv, argc);
-	}
-	result = rb_yield_values2(len, RARRAY_PTR(args));
-	RB_GC_GUARD(args);
+    if (RTEST(move_next)) {
+        return result;
+    } else {
+        return Qundef;
     }
-    if (result == Qundef) rb_iter_break();
-    return Qnil;
 }
 
 static VALUE
-lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv)
+lazy_iterator_block(VALUE val, VALUE m, int argc, VALUE *argv)
 {
     VALUE result;
-    result = rb_funcall2(m, id_yield, argc, argv);
-    if (result == Qundef) rb_iter_break();
-    return Qnil;
-}
+    VALUE yielder = RARRAY_PTR(m)[0];
 
-static VALUE
-lazy_init_block_i(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val);
-    return Qnil;
+    result = process_element(enumerator_ptr(RARRAY_PTR(m)[1]), val);
+    if (result != Qundef) {
+        return yielder_yield(yielder, rb_ary_new3(1, result));
+    } else {
+        return Qnil;
+    }
 }
 
 static VALUE
-lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv)
+lazy_generator_block(VALUE val, VALUE m, int argc, VALUE *argv)
 {
-    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_yielder, val);
-    return Qnil;
+    VALUE obj = RARRAY_PTR(m)[0];
+    VALUE enumerator = RARRAY_PTR(m)[1];
+
+    return rb_block_call(obj, id_each, 0, Qnil,
+            lazy_iterator_block, rb_ary_new3(2, val, enumerator));
 }
 
 static VALUE
 lazy_initialize(int argc, VALUE *argv, VALUE self)
 {
-    VALUE obj, meth;
     VALUE generator;
-    int offset;
+    VALUE obj;
+    struct enumerator *ptr;
 
-    if (argc < 1) {
-	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..)", argc);
-    }
-    else {
-	obj = argv[0];
-	if (argc == 1) {
-	    meth = sym_each;
-	    offset = 1;
-	}
-	else {
-	    meth = argv[1];
-	    offset = 2;
-	}
-    }
+    obj = argv[0];
     generator = generator_allocate(rb_cGenerator);
-    rb_block_call(generator, id_initialize, 0, 0,
-		  (rb_block_given_p() ? lazy_init_block_i : lazy_init_block),
-		  obj);
-    enumerator_init(self, generator, meth, argc - offset, argv + offset);
-    rb_ivar_set(self, id_receiver, obj);
+    rb_block_call(generator, rb_intern("initialize"), 0, Qnil,
+            lazy_generator_block, rb_ary_new3(2, obj, self));
+    enumerator_init(self, generator, sym_each, 0, Qnil);
+    ptr = enumerator_ptr(self);
+    ptr->lazy = Qtrue;
+    ptr->procs = rb_ary_new();
 
     return self;
 }
 
 static VALUE
-lazy_set_method(VALUE lazy, VALUE args)
+create_proc_entry(enum proc_entry_type proc_type)
 {
-    ID id = rb_frame_this_func();
-    rb_ivar_set(lazy, id_method, ID2SYM(id));
-    if (NIL_P(args)) {
-	/* Qfalse indicates that the arguments are empty */
-	rb_ivar_set(lazy, id_arguments, Qfalse);
-    }
-    else {
-	rb_ivar_set(lazy, id_arguments, args);
-    }
-    return lazy;
-}
+    struct proc_entry *entry;
+    VALUE entry_obj;
 
-/*
- * call-seq:
- *   e.lazy -> lazy_enumerator
- *
- * Returns a lazy enumerator, whose methods map/collect,
- * flat_map/collect_concat, select/find_all, reject, grep, zip, take,
- * take_while, drop, drop_while, and cycle enumerate values only on an
- * as-needed basis.  However, if a block is given to zip or cycle, values
- * are enumerated immediately.
- *
- * === Example
- *
- * The following program finds pythagorean triples:
- *
- *   def pythagorean_triples
- *     (1..Float::INFINITY).lazy.flat_map {|z|
- *       (1..z).flat_map {|x|
- *         (x..z).select {|y|
- *           x**2 + y**2 == z**2
- *         }.map {|y|
- *           [x, y, z]
- *         }
- *       }
- *     }
- *   end
- *   # show first ten pythagorean triples
- *   p pythagorean_triples.take(10).force # take is lazy, so force is needed
- *   p pythagorean_triples.first(10)      # first is eager
- *   # show pythagorean triples less than 100
- *   p pythagorean_triples.take_while { |*, z| z < 100 }.force
- */
-static VALUE
-enumerable_lazy(VALUE obj)
-{
-    VALUE result;
+    entry_obj = Data_Make_Struct(rb_cObject, struct proc_entry, 0, RUBY_DEFAULT_FREE, entry);
+    Data_Get_Struct(entry_obj, struct proc_entry, entry);
+    entry->proc = rb_block_proc();
+    entry->type = proc_type;
 
-    result = rb_class_new_instance(1, &obj, rb_cLazy);
-    /* Qfalse indicates that the Enumerator::Lazy has no method name */
-    rb_ivar_set(result, id_method, Qfalse);
-    return result;
-}
-
-static VALUE
-lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
-
-    rb_funcall(argv[0], id_yield, 1, result);
-    return Qnil;
+    return entry_obj;
 }
 
 static VALUE
 lazy_map(VALUE obj)
 {
-    if (!rb_block_given_p()) {
-	rb_raise(rb_eArgError, "tried to call lazy map without a block");
-    }
-
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 lazy_map_func, 0),
-			   Qnil);
-}
-
-static VALUE
-lazy_flat_map_i(VALUE i, VALUE yielder, int argc, VALUE *argv)
-{
-    return rb_funcall2(yielder, id_yield, argc, argv);
-}
-
-static VALUE
-lazy_flat_map_each(VALUE obj)
-{
-    NODE *memo = RNODE(obj);
-    rb_block_call(memo->u1.value, id_each, 0, 0, lazy_flat_map_i,
-		  memo->u2.value);
-    return Qnil;
-}
-
-static VALUE
-lazy_flat_map_to_ary(VALUE obj)
-{
-    NODE *memo = RNODE(obj);
-    VALUE ary = rb_check_array_type(memo->u1.value);
-    if (NIL_P(ary)) {
-	rb_funcall(memo->u2.value, id_yield, 1, memo->u1.value);
-    }
-    else {
-	long i;
-	for (i = 0; i < RARRAY_LEN(ary); i++) {
-	    rb_funcall(memo->u2.value, id_yield, 1, RARRAY_PTR(ary)[i]);
-	}
-    }
-    return Qnil;
-}
-
-static VALUE
-lazy_flat_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
-    if (TYPE(result) == T_ARRAY) {
-	long i;
-	for (i = 0; i < RARRAY_LEN(result); i++) {
-	    rb_funcall(argv[0], id_yield, 1, RARRAY_PTR(result)[i]);
-	}
-    }
-    else {
-	NODE *memo;
-	memo = NEW_MEMO(result, argv[0], 0);
-	rb_rescue2(lazy_flat_map_each, (VALUE) memo,
-		   lazy_flat_map_to_ary, (VALUE) memo,
-		   rb_eNoMethodError, (VALUE)0);
-    }
-    return Qnil;
-}
-
-static VALUE
-lazy_flat_map(VALUE obj)
-{
-    if (!rb_block_given_p()) {
-	rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
-    }
-
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 lazy_flat_map_func, 0),
-			   Qnil);
-}
+    struct enumerator *e = enumerator_ptr(obj);
 
-static VALUE
-lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
+    rb_ary_push(e->procs, create_proc_entry(T_PROC_MAP));
 
-    if (RTEST(rb_yield(element))) {
-	return rb_funcall(argv[0], id_yield, 1, element);
-    }
-    return Qnil;
+    return obj;
 }
 
 static VALUE
 lazy_select(VALUE obj)
 {
-    if (!rb_block_given_p()) {
-	rb_raise(rb_eArgError, "tried to call lazy select without a block");
-    }
-
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 lazy_select_func, 0),
-			   Qnil);
-}
-
-static VALUE
-lazy_reject_func(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
-
-    if (!RTEST(rb_yield(element))) {
-	return rb_funcall(argv[0], id_yield, 1, element);
-    }
-    return Qnil;
-}
-
-static VALUE
-lazy_reject(VALUE obj)
-{
-    if (!rb_block_given_p()) {
-	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
-    }
-
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 lazy_reject_func, 0),
-			   Qnil);
-}
-
-static VALUE
-lazy_grep_func(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
-    VALUE result = rb_funcall(m, id_eqq, 1, i);
-
-    if (RTEST(result)) {
-	rb_funcall(argv[0], id_yield, 1, i);
-    }
-    return Qnil;
-}
-
-static VALUE
-lazy_grep_iter(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
-    VALUE result = rb_funcall(m, id_eqq, 1, i);
-
-    if (RTEST(result)) {
-	rb_funcall(argv[0], id_yield, 1, rb_yield(i));
-    }
-    return Qnil;
-}
-
-static VALUE
-lazy_grep(VALUE obj, VALUE pattern)
-{
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 rb_block_given_p() ?
-					 lazy_grep_iter : lazy_grep_func,
-					 pattern),
-			   rb_ary_new3(1, pattern));
-}
-
-static VALUE
-call_next(VALUE obj)
-{
-    return rb_funcall(obj, id_next, 0);
-}
-
-static VALUE
-next_stopped(VALUE obj)
-{
-    return Qnil;
-}
-
-static VALUE
-lazy_zip_func(VALUE val, VALUE arg, int argc, VALUE *argv)
-{
-    VALUE yielder, ary, v;
-    long i;
-
-    yielder = argv[0];
-    ary = rb_ary_new2(RARRAY_LEN(arg) + 1);
-    rb_ary_push(ary, argv[1]);
-    for (i = 0; i < RARRAY_LEN(arg); i++) {
-	v = rb_rescue2(call_next, RARRAY_PTR(arg)[i], next_stopped, 0,
-		       rb_eStopIteration, (VALUE)0);
-	rb_ary_push(ary, v);
-    }
-    rb_funcall(yielder, id_yield, 1, ary);
-    return Qnil;
-}
-
-static VALUE
-lazy_zip(int argc, VALUE *argv, VALUE obj)
-{
-    VALUE ary;
-    int i;
-
-    if (rb_block_given_p()) {
-	return rb_call_super(argc, argv);
-    }
-    ary = rb_ary_new2(argc);
-    for (i = 0; i < argc; i++) {
-	rb_ary_push(ary, rb_funcall(argv[i], id_lazy, 0));
-    }
-
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 lazy_zip_func, ary),
-			   rb_ary_new4(argc, argv));
-}
-
-static VALUE
-lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
-{
-    NODE *memo = RNODE(args);
-
-    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
-    if (--memo->u3.cnt == 0) {
-	return Qundef;
-    }
-    else {
-	return Qnil;
-    }
-}
-
-static VALUE
-lazy_take(VALUE obj, VALUE n)
-{
-    NODE *memo;
-    long len = NUM2LONG(n);
-    int argc = 1;
-    VALUE argv[3];
-
-    if (len < 0) {
-	rb_raise(rb_eArgError, "attempt to take negative size");
-    }
-    argv[0] = obj;
-    if (len == 0) {
-	argv[1] = sym_cycle;
-	argv[2] = INT2NUM(0);
-	argc = 3;
-    }
-    memo = NEW_MEMO(0, 0, len);
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, argc, argv,
-					 lazy_take_func, (VALUE) memo),
-			   rb_ary_new3(1, n));
-}
-
-static VALUE
-lazy_take_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
-{
-    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
-    if (!RTEST(result)) return Qundef;
-    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
-    return Qnil;
-}
-
-static VALUE
-lazy_take_while(VALUE obj)
-{
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 lazy_take_while_func, 0),
-			   Qnil);
-}
-
-static VALUE
-lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
-{
-    NODE *memo = RNODE(args);
-
-    if (memo->u3.cnt == 0) {
-	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
-    }
-    else {
-	memo->u3.cnt--;
-    }
-    return Qnil;
-}
-
-static VALUE
-lazy_drop(VALUE obj, VALUE n)
-{
-    NODE *memo;
-    long len = NUM2LONG(n);
-
-    if (len < 0) {
-	rb_raise(rb_eArgError, "attempt to drop negative size");
-    }
-    memo = NEW_MEMO(0, 0, len);
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 lazy_drop_func, (VALUE) memo),
-			   rb_ary_new3(1, n));
-}
-
-static VALUE
-lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
-{
-    NODE *memo = RNODE(args);
-
-    if (!memo->u3.state && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
-	memo->u3.state = TRUE;
-    }
-    if (memo->u3.state) {
-	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
-    }
-    return Qnil;
-}
-
-static VALUE
-lazy_drop_while(VALUE obj)
-{
-    NODE *memo;
+    struct enumerator *e = enumerator_ptr(obj);
 
-    memo = NEW_MEMO(0, 0, FALSE);
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
-					 lazy_drop_while_func, (VALUE) memo),
-			   Qnil);
-}
+    rb_ary_push(e->procs, create_proc_entry(T_PROC_SELECT));
 
-static VALUE
-lazy_cycle_func(VALUE val, VALUE m, int argc, VALUE *argv)
-{
-    return rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+    return obj;
 }
 
 static VALUE
-lazy_cycle(int argc, VALUE *argv, VALUE obj)
+enumerable_lazy(VALUE self)
 {
-    VALUE args;
-    int len = rb_long2int((long)argc + 2);
-
-    if (rb_block_given_p()) {
-	return rb_call_super(argc, argv);
-    }
-    args = rb_ary_tmp_new(len);
-    rb_ary_push(args, obj);
-    rb_ary_push(args, sym_cycle);
-    if (argc > 0) {
-	rb_ary_cat(args, argv, argc);
-    }
-    return lazy_set_method(rb_block_call(rb_cLazy, id_new, len,
-					 RARRAY_PTR(args), lazy_cycle_func,
-					 args /* prevent from GC */),
-			   rb_ary_new4(argc, argv));
+    return rb_class_new_instance(1, &self, rb_cLazy);
 }
 
-static VALUE
-lazy_lazy(VALUE obj)
-{
-    return obj;
-}
+/* Lazy Enumerator methods */
+//static VALUE
+//lazy_init_iterator(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    VALUE result;
+//    if (argc == 1) {
+//	VALUE args[2];
+//	args[0] = m;
+//	args[1] = val;
+//	result = rb_yield_values2(2, args);
+//    }
+//    else {
+//	VALUE args;
+//	int len = rb_long2int((long)argc + 1);
+//
+//	args = rb_ary_tmp_new(len);
+//	rb_ary_push(args, m);
+//	if (argc > 0) {
+//	    rb_ary_cat(args, argv, argc);
+//	}
+//	result = rb_yield_values2(len, RARRAY_PTR(args));
+//	RB_GC_GUARD(args);
+//    }
+//    if (result == Qundef) rb_iter_break();
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_init_yielder(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    VALUE result;
+//    result = rb_funcall2(m, id_yield, argc, argv);
+//    if (result == Qundef) rb_iter_break();
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_init_block_i(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_iterator, val);
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_init_block(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    rb_block_call(m, id_each, argc-1, argv+1, lazy_init_yielder, val);
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_initialize(int argc, VALUE *argv, VALUE self)
+//{
+//    VALUE obj, meth;
+//    VALUE generator;
+//    int offset;
+//
+//    if (argc < 1) {
+//	rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..)", argc);
+//    }
+//    else {
+//	obj = argv[0];
+//	if (argc == 1) {
+//	    meth = sym_each;
+//	    offset = 1;
+//	}
+//	else {
+//	    meth = argv[1];
+//	    offset = 2;
+//	}
+//    }
+//    generator = generator_allocate(rb_cGenerator);
+//    rb_block_call(generator, id_initialize, 0, 0,
+//		  (rb_block_given_p() ? lazy_init_block_i : lazy_init_block),
+//		  obj);
+//    enumerator_init(self, generator, meth, argc - offset, argv + offset);
+//    rb_ivar_set(self, id_receiver, obj);
+//
+//    return self;
+//}
+//
+//static VALUE
+//lazy_set_method(VALUE lazy, VALUE args)
+//{
+//    ID id = rb_frame_this_func();
+//    rb_ivar_set(lazy, id_method, ID2SYM(id));
+//    if (NIL_P(args)) {
+//	/* Qfalse indicates that the arguments are empty */
+//	rb_ivar_set(lazy, id_arguments, Qfalse);
+//    }
+//    else {
+//	rb_ivar_set(lazy, id_arguments, args);
+//    }
+//    return lazy;
+//}
+//
+///*
+// * call-seq:
+// *   e.lazy -> lazy_enumerator
+// *
+// * Returns a lazy enumerator, whose methods map/collect,
+// * flat_map/collect_concat, select/find_all, reject, grep, zip, take,
+// * take_while, drop, drop_while, and cycle enumerate values only on an
+// * as-needed basis.  However, if a block is given to zip or cycle, values
+// * are enumerated immediately.
+// *
+// * === Example
+// *
+// * The following program finds pythagorean triples:
+// *
+// *   def pythagorean_triples
+// *     (1..Float::INFINITY).lazy.flat_map {|z|
+// *       (1..z).flat_map {|x|
+// *         (x..z).select {|y|
+// *           x**2 + y**2 == z**2
+// *         }.map {|y|
+// *           [x, y, z]
+// *         }
+// *       }
+// *     }
+// *   end
+// *   # show first ten pythagorean triples
+// *   p pythagorean_triples.take(10).force # take is lazy, so force is needed
+// *   p pythagorean_triples.first(10)      # first is eager
+// *   # show pythagorean triples less than 100
+// *   p pythagorean_triples.take_while { |*, z| z < 100 }.force
+// */
+//static VALUE
+//enumerable_lazy(VALUE obj)
+//{
+//    VALUE result;
+//
+//    result = rb_class_new_instance(1, &obj, rb_cLazy);
+//    /* Qfalse indicates that the Enumerator::Lazy has no method name */
+//    rb_ivar_set(result, id_method, Qfalse);
+//    return result;
+//}
+//
+//static VALUE
+//lazy_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
+//
+//    rb_funcall(argv[0], id_yield, 1, result);
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_map(VALUE obj)
+//{
+//    if (!rb_block_given_p()) {
+//	rb_raise(rb_eArgError, "tried to call lazy map without a block");
+//    }
+//
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 lazy_map_func, 0),
+//			   Qnil);
+//}
+//
+//static VALUE
+//lazy_flat_map_i(VALUE i, VALUE yielder, int argc, VALUE *argv)
+//{
+//    return rb_funcall2(yielder, id_yield, argc, argv);
+//}
+//
+//static VALUE
+//lazy_flat_map_each(VALUE obj)
+//{
+//    NODE *memo = RNODE(obj);
+//    rb_block_call(memo->u1.value, id_each, 0, 0, lazy_flat_map_i,
+//		  memo->u2.value);
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_flat_map_to_ary(VALUE obj)
+//{
+//    NODE *memo = RNODE(obj);
+//    VALUE ary = rb_check_array_type(memo->u1.value);
+//    if (NIL_P(ary)) {
+//	rb_funcall(memo->u2.value, id_yield, 1, memo->u1.value);
+//    }
+//    else {
+//	long i;
+//	for (i = 0; i < RARRAY_LEN(ary); i++) {
+//	    rb_funcall(memo->u2.value, id_yield, 1, RARRAY_PTR(ary)[i]);
+//	}
+//    }
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_flat_map_func(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
+//    if (TYPE(result) == T_ARRAY) {
+//	long i;
+//	for (i = 0; i < RARRAY_LEN(result); i++) {
+//	    rb_funcall(argv[0], id_yield, 1, RARRAY_PTR(result)[i]);
+//	}
+//    }
+//    else {
+//	NODE *memo;
+//	memo = NEW_MEMO(result, argv[0], 0);
+//	rb_rescue2(lazy_flat_map_each, (VALUE) memo,
+//		   lazy_flat_map_to_ary, (VALUE) memo,
+//		   rb_eNoMethodError, (VALUE)0);
+//    }
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_flat_map(VALUE obj)
+//{
+//    if (!rb_block_given_p()) {
+//	rb_raise(rb_eArgError, "tried to call lazy flat_map without a block");
+//    }
+//
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 lazy_flat_map_func, 0),
+//			   Qnil);
+//}
+//
+//static VALUE
+//lazy_select_func(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
+//
+//    if (RTEST(rb_yield(element))) {
+//	return rb_funcall(argv[0], id_yield, 1, element);
+//    }
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_select(VALUE obj)
+//{
+//    if (!rb_block_given_p()) {
+//	rb_raise(rb_eArgError, "tried to call lazy select without a block");
+//    }
+//
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 lazy_select_func, 0),
+//			   Qnil);
+//}
+//
+//static VALUE
+//lazy_reject_func(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    VALUE element = rb_enum_values_pack(argc - 1, argv + 1);
+//
+//    if (!RTEST(rb_yield(element))) {
+//	return rb_funcall(argv[0], id_yield, 1, element);
+//    }
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_reject(VALUE obj)
+//{
+//    if (!rb_block_given_p()) {
+//	rb_raise(rb_eArgError, "tried to call lazy reject without a block");
+//    }
+//
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 lazy_reject_func, 0),
+//			   Qnil);
+//}
+//
+//static VALUE
+//lazy_grep_func(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
+//    VALUE result = rb_funcall(m, id_eqq, 1, i);
+//
+//    if (RTEST(result)) {
+//	rb_funcall(argv[0], id_yield, 1, i);
+//    }
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_grep_iter(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    VALUE i = rb_enum_values_pack(argc - 1, argv + 1);
+//    VALUE result = rb_funcall(m, id_eqq, 1, i);
+//
+//    if (RTEST(result)) {
+//	rb_funcall(argv[0], id_yield, 1, rb_yield(i));
+//    }
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_grep(VALUE obj, VALUE pattern)
+//{
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 rb_block_given_p() ?
+//					 lazy_grep_iter : lazy_grep_func,
+//					 pattern),
+//			   rb_ary_new3(1, pattern));
+//}
+//
+//static VALUE
+//call_next(VALUE obj)
+//{
+//    return rb_funcall(obj, id_next, 0);
+//}
+//
+//static VALUE
+//next_stopped(VALUE obj)
+//{
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_zip_func(VALUE val, VALUE arg, int argc, VALUE *argv)
+//{
+//    VALUE yielder, ary, v;
+//    long i;
+//
+//    yielder = argv[0];
+//    ary = rb_ary_new2(RARRAY_LEN(arg) + 1);
+//    rb_ary_push(ary, argv[1]);
+//    for (i = 0; i < RARRAY_LEN(arg); i++) {
+//	v = rb_rescue2(call_next, RARRAY_PTR(arg)[i], next_stopped, 0,
+//		       rb_eStopIteration, (VALUE)0);
+//	rb_ary_push(ary, v);
+//    }
+//    rb_funcall(yielder, id_yield, 1, ary);
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_zip(int argc, VALUE *argv, VALUE obj)
+//{
+//    VALUE ary;
+//    int i;
+//
+//    if (rb_block_given_p()) {
+//	return rb_call_super(argc, argv);
+//    }
+//    ary = rb_ary_new2(argc);
+//    for (i = 0; i < argc; i++) {
+//	rb_ary_push(ary, rb_funcall(argv[i], id_lazy, 0));
+//    }
+//
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 lazy_zip_func, ary),
+//			   rb_ary_new4(argc, argv));
+//}
+//
+//static VALUE
+//lazy_take_func(VALUE val, VALUE args, int argc, VALUE *argv)
+//{
+//    NODE *memo = RNODE(args);
+//
+//    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+//    if (--memo->u3.cnt == 0) {
+//	return Qundef;
+//    }
+//    else {
+//	return Qnil;
+//    }
+//}
+//
+//static VALUE
+//lazy_take(VALUE obj, VALUE n)
+//{
+//    NODE *memo;
+//    long len = NUM2LONG(n);
+//    int argc = 1;
+//    VALUE argv[3];
+//
+//    if (len < 0) {
+//	rb_raise(rb_eArgError, "attempt to take negative size");
+//    }
+//    argv[0] = obj;
+//    if (len == 0) {
+//	argv[1] = sym_cycle;
+//	argv[2] = INT2NUM(0);
+//	argc = 3;
+//    }
+//    memo = NEW_MEMO(0, 0, len);
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, argc, argv,
+//					 lazy_take_func, (VALUE) memo),
+//			   rb_ary_new3(1, n));
+//}
+//
+//static VALUE
+//lazy_take_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
+//{
+//    VALUE result = rb_yield_values2(argc - 1, &argv[1]);
+//    if (!RTEST(result)) return Qundef;
+//    rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_take_while(VALUE obj)
+//{
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 lazy_take_while_func, 0),
+//			   Qnil);
+//}
+//
+//static VALUE
+//lazy_drop_func(VALUE val, VALUE args, int argc, VALUE *argv)
+//{
+//    NODE *memo = RNODE(args);
+//
+//    if (memo->u3.cnt == 0) {
+//	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+//    }
+//    else {
+//	memo->u3.cnt--;
+//    }
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_drop(VALUE obj, VALUE n)
+//{
+//    NODE *memo;
+//    long len = NUM2LONG(n);
+//
+//    if (len < 0) {
+//	rb_raise(rb_eArgError, "attempt to drop negative size");
+//    }
+//    memo = NEW_MEMO(0, 0, len);
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 lazy_drop_func, (VALUE) memo),
+//			   rb_ary_new3(1, n));
+//}
+//
+//static VALUE
+//lazy_drop_while_func(VALUE val, VALUE args, int argc, VALUE *argv)
+//{
+//    NODE *memo = RNODE(args);
+//
+//    if (!memo->u3.state && !RTEST(rb_yield_values2(argc - 1, &argv[1]))) {
+//	memo->u3.state = TRUE;
+//    }
+//    if (memo->u3.state) {
+//	rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+//    }
+//    return Qnil;
+//}
+//
+//static VALUE
+//lazy_drop_while(VALUE obj)
+//{
+//    NODE *memo;
+//
+//    memo = NEW_MEMO(0, 0, FALSE);
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj,
+//					 lazy_drop_while_func, (VALUE) memo),
+//			   Qnil);
+//}
+//
+//static VALUE
+//lazy_cycle_func(VALUE val, VALUE m, int argc, VALUE *argv)
+//{
+//    return rb_funcall2(argv[0], id_yield, argc - 1, argv + 1);
+//}
+//
+//static VALUE
+//lazy_cycle(int argc, VALUE *argv, VALUE obj)
+//{
+//    VALUE args;
+//    int len = rb_long2int((long)argc + 2);
+//
+//    if (rb_block_given_p()) {
+//	return rb_call_super(argc, argv);
+//    }
+//    args = rb_ary_tmp_new(len);
+//    rb_ary_push(args, obj);
+//    rb_ary_push(args, sym_cycle);
+//    if (argc > 0) {
+//	rb_ary_cat(args, argv, argc);
+//    }
+//    return lazy_set_method(rb_block_call(rb_cLazy, id_new, len,
+//					 RARRAY_PTR(args), lazy_cycle_func,
+//					 args /* prevent from GC */),
+//			   rb_ary_new4(argc, argv));
+//}
+//
+//static VALUE
+//lazy_lazy(VALUE obj)
+//{
+//    return obj;
+//}
 
 /*
  * Document-class: StopIteration
@@ -1750,22 +1879,22 @@ InitVM_Enumerator(void)
     rb_define_method(rb_mEnumerable, "lazy", enumerable_lazy, 0);
     rb_define_method(rb_cLazy, "initialize", lazy_initialize, -1);
     rb_define_method(rb_cLazy, "map", lazy_map, 0);
-    rb_define_method(rb_cLazy, "collect", lazy_map, 0);
-    rb_define_method(rb_cLazy, "flat_map", lazy_flat_map, 0);
-    rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0);
+    //rb_define_method(rb_cLazy, "collect", lazy_map, 0);
+    //rb_define_method(rb_cLazy, "flat_map", lazy_flat_map, 0);
+    //rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0);
     rb_define_method(rb_cLazy, "select", lazy_select, 0);
     rb_define_method(rb_cLazy, "find_all", lazy_select, 0);
-    rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
-    rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
-    rb_define_method(rb_cLazy, "zip", lazy_zip, -1);
-    rb_define_method(rb_cLazy, "take", lazy_take, 1);
-    rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0);
-    rb_define_method(rb_cLazy, "drop", lazy_drop, 1);
-    rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0);
-    rb_define_method(rb_cLazy, "cycle", lazy_cycle, -1);
-    rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0);
-
-    rb_define_alias(rb_cLazy, "force", "to_a");
+    //rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
+    //rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
+    //rb_define_method(rb_cLazy, "zip", lazy_zip, -1);
+    //rb_define_method(rb_cLazy, "take", lazy_take, 1);
+    //rb_define_method(rb_cLazy, "take_while", lazy_take_while, 0);
+    //rb_define_method(rb_cLazy, "drop", lazy_drop, 1);
+    //rb_define_method(rb_cLazy, "drop_while", lazy_drop_while, 0);
+    //rb_define_method(rb_cLazy, "cycle", lazy_cycle, -1);
+    //rb_define_method(rb_cLazy, "lazy", lazy_lazy, 0);
+
+    //rb_define_alias(rb_cLazy, "force", "to_a");
 
     rb_eStopIteration = rb_define_class("StopIteration", rb_eIndexError);
     rb_define_method(rb_eStopIteration, "result", stop_result, 0);
