From: Robert Dober Date: 2007-06-24T20:05:20+09:00 Subject: Re: Enumerator for elementwise too? [was: Changing enum_obj] On 6/24/07, Trans wrote: > > > On Jun 24, 4:15 am, "Robert Dober" wrote: > > On 6/24/07, Trans wrote: > > > > > > > > > Well, I might as well bring up the reason I asked about enum_obj... > > > > > Spending some time improving Facets' Elementor class concept and > > > #every method, I find this possible utter simplification: > > > > > class Enumerable::Enumerator > > > def method_missing(sym, *args, &blk) > > > self.class.new(collect{ |e| e.send(sym, *args, &blk) }) > > > end > > > end > > > > > Example: > > > > > a = [1,2,3] > > > e = a.to_enum > > > e += 3 > > > e *= 2 > > > e.to_a #=> [8,10,11] > > > > > T. > > > > Apart the magic dot notation that is *exactly* what I am doing in Labrador. > > Well I cannot expect blocks in this way as they have the original > > purpose and are sent to map. > > > > module Enumerable > > > > alias_method :__map_l1, :map > > # > > # The behavior of map {...} is unchanged. > > # map(arg1, *rest) simply is translated to map{ |ele| ele.send(arg1, *rest) } > > # map(arg1, *rest){...} is translated to map{|ele| > > ele.send(arg1,*rest}.map{...} > > # map without any arguments creates a Dispatcher Proxy that will > > dispatch all messages > > # to the elements of the receiver. > > # > > # All the following expressions evaluate therefore to the same result: > > # ary=[*0..9] > > # ary.map{ |x| x + 1} > > # ary.map(:succ) > > # ary.map.succ > > # ary.map(:+, 1) > > # ary.map + 1 > > def map *args, &blk > > return Labrador::Dispatcher.new( self, :map ) if args.empty? && blk.nil? > > return __map_l1( &blk ) if args.empty? > > return __map_l1 { |x| x.send( *args ) } if blk.nil? > > __map_l1 { |x| x.send( *args ) }.__map_l1( &blk ) > > end # def map *args, &blk > > > > end # module Enumerable > > Ah, so you overloaded #map with this functionality. That's similar to > what I had done, but I used a different method name, #every, which is > defined: Facets is great but Labrador is mine, what does that mean: I have the luxury to do things that scale badly and break compatibility, -- I have to make the documentation clear about this in the next version. Facets is a General Purpose Library and cannot afford that luxury, so it is very clear why you have #every -- a tempting idea not to overload map, even in an experimental package as my dog package. Yet another advantage, I just change the name, nobody can complain... OTH I am surprised that #every corresponds to #map, from its naming on would say it should correspond to #each. > > module Enumerable > def every > @_functor_every ||= Functor.new do |op,*args| > self.collect{ |a| a.send(op,*args) } > end > end > end > I gotta look at your Functors again, maybe I can steal a little bit from you;) > Both are limited in one common respect. They can't be chained along > without repeated invocation, eg. it's not > > [1,2,3].map * 6 + 4 That is even broken in Labrador, so much work to do :( irb(main):001:0> require 'labrador' => true irb(main):002:0> [1,2,3].map + 2 => [3, 4, 5] irb(main):003:0> [1,2,3].map + 2 * 3 => [7, 8, 9] *** Arrrgh > > We have to do: > > ([1,2,3].map * 6).map + 4 > > Not quite as bad for #map, as opposed to #every, being shorter, but it > would still be nice to chain. Of course, to do that one must > explicitly #to_a the final result per my original Enumerator example. > > One thing you might want to consider, Ruby 1.9+ returns an Enumerator > for #map without a block, could pose some compatibility issues in the > future. That is a good thing, and thanks for pointing it out, looking for a different name for #map now ;) Though, I have to admit I'm not quite sure what a #map based > Enumerator is good for -- when you run #each on it, it acts like > #map !!! > > T. > Cheers Robert -- You see things; and you say Why? But I dream things that never were; and I say Why not? -- George Bernard Shaw