From: Intransition Date: 2010-04-11T03:05:29+09:00 Subject: Re: Is it possible, a fully general Enumerable#recursive ? On Apr 9, 6:38 pm, Colin Bartlett wrote: > I'm not sure that it is a bug. > > http://www.ruby-doc.org/ruby-1.9/classes/Enumerable.html#M002713 > enum.map {| obj | block } => array > Returns a new array with the results of running block once for every > element in enum. > > http://www.ruby-doc.org/ruby-1.9/classes/Enumerable.src/M002713.html > static VALUE > enum_collect(VALUE obj) > { >     VALUE ary; >     RETURN_ENUMERATOR(obj, 0, 0); >     ary = rb_ary_new(); >     rb_block_call(obj, id_each, 0, 0, collect_i, ary); >     return ary; > > } > > The following is Intransition's methods with some added info. > It looks to me as though two things are happening. > > 1. Using #map inside #visit combined with using Enumerable#map >    seems to (within #visit) produce the structure of the original array, >    but with nil values instead of the original values. >    (Changing #map inside #visit to #each gets back the original values.) > > 2. Irrespective of the internal results from #visit, Enumerable#map >    collects the successive results of the block for Enumerable#map >    into a new (flat) array. > >   module Enumerable >     def visit(&block) > puts "#=> Enumerable#visit: self=0x#{self.object_id}= #{self.inspect}" >       if block_given? then result = map do |e| e.visit(&block) end >       else result = to_enum(:visit) >       end > puts "#=> Enumerable#visit: result=0x#{result.object_id}= #{result.inspect}" >       result >     end >   end > >   class Object >     def visit(&block) ; block.call(self) ; end >   end > > arr = [ 10, [ 210 ], 30 ] > it = arr.visit > #=> Enumerable#visit: self=0x13928400= [10, [210], 30] > #=> Enumerable#visit: result=0x13927776= # > > puts ; rr = it.each{ |x| x+7 } > #=> Enumerable#visit: self=0x13928400= [10, [210], 30] > #=> Enumerable#visit: self=0x13928416= [210] > #=> Enumerable#visit: result=0x1562576= [217] > #=> Enumerable#visit: result=0x13926848= [17, [217], 37] > puts "#=> rr=0x#{rr.object_id}= #{rr.inspect}" > #=> rr=0x13926848= [17, [217], 37] > > puts ; rr = it.map{ |x| x+7 } > #=> Enumerable#visit: self=0x13928400= [10, [210], 30] > #=> Enumerable#visit: self=0x13928416= [210] > #=> Enumerable#visit: result=0x1559360= [nil] > #=> Enumerable#visit: result=0x1559840= [nil, [nil], nil] > puts "#=> rr=0x#{rr.object_id}= #{rr.inspect}" > #=> rr=0x1561088= [17, 217, 37] > > # Note that the last Enumerable#visit result from it.map > # has the same structure as the original nested array > # (albeit with nil values - dunno why at the moment), > # but that the return value of it.map is a flat array > # of the successive results of the block calculation. > > Changing: >       if block_given? then result = map do |e| e.visit(&block) end > to: >       if block_given? then result = each do |e| e.visit(&block) end > gives for it.map: > > puts ; rr = it.map{ |x| x+7 } > #=> Enumerable#visit: self=0x14484864= [10, [210], 30] > #=> Enumerable#visit: self=0x14484896= [210] > #=> Enumerable#visit: result=0x14484896= [210] > #=> Enumerable#visit: result=0x14484864= [10, [210], 30] > puts "#=> rr=0x#{rr.object_id}= #{rr.inspect}" > #=> rr=0x1298112= [17, 217, 37] Thanks, that helped me understand a little better. After working on this for far too long, I have concluded that a highly generalized implementation of recursion for all (or at least most) enumerable methods not feasible. But there are still many things in common between recursion methods, so instead I have created a Recursor class to act something like an Enumerator for recursive operations. Thanks for the help.