From: Intransition on
For the last couple of days I've been trying to write an Enumerable
method called #recursive. Rather than create a bunch of methods like
#recursive_each, #recursive_map, #recursive_sort, etc. I figured that
it should be possible to create a single #recursive method that
returned an Enumerator, or barring that a Functor, that would handle
any enumerable method, e.g. recursive.each, recursive.map,
recursive.sort, and so on. But I have yet to figure out fully general
solution.

My nearest success thus far is:

require 'facets/functor'

module Enumerable

def recursive
Functor.new do |op,*a,&b|
__send__(op) do |e|
if self.class === e
e.recursive.__send__(op,*a,&b)
else
b.call(e)
end
end
end
end

end

This works for #each and #map but not #sort.

Can anyone think of a better solution?


From: David Masover on
On Wednesday 07 April 2010 04:49:15 pm Intransition wrote:
> For the last couple of days I've been trying to write an Enumerable
> method called #recursive. Rather than create a bunch of methods like
> #recursive_each, #recursive_map, #recursive_sort, etc. I figured that
> it should be possible to create a single #recursive method that
> returned an Enumerator,

Yes!

> or barring that a Functor,

What's a Functor in this context? We already have proc objects, which is
traditionally what "functor" means...

> This works for #each and #map but not #sort.

#sort isn't a method of Enumerable, it's a method of Array.

> Can anyone think of a better solution?

Probably, but I'm not sure what it would look like. What's your use case --
how would I actually use this to, say, generate an infinite stream of
fibbonacci numbers?

I guess I don't really see why you'd define it in terms of an enumerable (in
that case, you probably want inject).

From: Intransition on


On Apr 7, 11:51 pm, David Masover <ni...(a)slaphack.com> wrote:
> On Wednesday 07 April 2010 04:49:15 pm Intransition wrote:
>
> > For the last couple of days I've been trying to write an Enumerable
> > method called #recursive. Rather than create a bunch of methods like
> > #recursive_each, #recursive_map, #recursive_sort, etc. I figured that
> > it should be possible to create a single #recursive method that
> > returned an Enumerator,
>
> Yes!
>
> > or barring that a Functor,
>
> What's a Functor in this context? We already have proc objects, which is
> traditionally what "functor" means...

Functor is defined as:

class Functor
private(*instance_methods.select { |m| m !~ /(^__|^binding$)/ })
def initialize(&function)
@function = function
end
def to_proc
@function
end
def method_missing(op, *args, &blk)
@function.call(op, *args, &blk)
end
end

#method_missing is what makes it different from a Proc.

> > This works for #each and #map but not #sort.
>
> #sort isn't a method of Enumerable, it's a method of Array.

It seems to be according to ri.

> > Can anyone think of a better solution?
>
> Probably, but I'm not sure what it would look like. What's your use case --
> how would I actually use this to, say, generate an infinite stream of
> fibbonacci numbers?

I don't think anyone can generate that seeing that it's infinite and
all ;-)

> I guess I don't really see why you'd define it in terms of an enumerable (in
> that case, you probably want inject).

Perhaps Array is the more appropriate place for it.

From: Intransition on
On Apr 7, 5:49 pm, Intransition <transf...(a)gmail.com> wrote:
> For the last couple of days I've been trying to write an Enumerable
> method called #recursive. Rather than create a bunch of methods like
> #recursive_each, #recursive_map, #recursive_sort, etc. I figured that
> it should be possible to create a single #recursive method that
> returned an Enumerator, or barring that a Functor, that would handle
> any enumerable method, e.g. recursive.each, recursive.map,
> recursive.sort, and so on. But I have yet to figure out fully general
> solution.

Working on this more I currently have the method #visit (see the code
below). It almost works, but it has this one issue that makes no sense
to me, and I wonder what is going on under the hood in Enumerator for
it do this. It has the air of a bug to me --or at least a feature
deficiency.

Notice:

[1, 2, 3, ['a', 'b', 'c'] ].visit{ |x| x.succ }
=> [2, 3, 4, ["b", "c", "d"]]

But using Enumerator:

[1, 2, 3, ['a', 'b', 'c'] ].visit.map{ |x| x.succ }
=> [2, 3, 4, "b", "c", "d"]

Why is it flattening the result?

Here's the code for #visit:

module Enumerable

def visit(&block)
if block_given?
map do |e|
e.visit(&block)
end
else
to_enum(:visit)
end
end

end

class Object

def visit(&block)
block.call(self)
end

end

class String

# This is needed for Ruby 1.8
def visit(&block)
block.call(self)
end

end

From: Robert Dober on
On Thu, Apr 8, 2010 at 5:51 AM, David Masover <ninja(a)slaphack.com> wrote:
> On Wednesday 07 April 2010 04:49:15 pm Intransition wrote:
<snip>
>
>> This works for #each and #map but not #sort.
>
> #sort isn't a method of Enumerable, it's a method of Array.
ruby-1.9.1-p378 > Enumerable.instance_methods.grep /sort/
=> [:sort, :sort_by]
However you will need to define #<=> on the return value of recursive.
HTH
R.
--
Learning without thought is labor lost; thought without learning is perilous.”
--- Confucius

 |  Next  |  Last
Pages: 1 2 3 4 5 6
Prev: what is the meaning of \A and \Z
Next: win32ole question