Forum: Ruby-core [ruby-trunk - Feature #6552][Open] Enumerator::Generator:select should return another Enumerator::Ge

Posted by eike.rb (Eike Dierks) (Guest)
on 2012-06-06 23:47
(Received via mailing list)
Issue #6552 has been reported by eike.rb (Eike Dierks).

----------------------------------------
Feature #6552: Enumerator::Generator:select should return another 
Enumerator::Generator
https://bugs.ruby-lang.org/issues/6552

Author: eike.rb (Eike Dierks)
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 1.9.3


The current implementation of Enumerator:select fails when applied to an 
open ended Enumerator:Generator,
resulting in an endless loop.

In the current implementation, :select seems to collect all values from 
the enumerator before applying the selection.
If that Enumeration is not bound, this results in an endless loop.

Instead, applying :select to a Generator should be applied to each 
object in turn and should itself return a Enumerator::Generator.

For example to select the first 5 even numbers starting at 123 should 
work as:
    (123..Float::INFINITY).select{|n|n.even?}.take(5)
but this currently results in an endless loop.

The same problem applies for :map and some other operators on 
Enumerations

However changing :select and :map to make them work with open ended 
Enumerations
might also change the api contract as they are currently defined to 
return an array.


We might want to have a look at the SICSP on streams,
    http://mitpress.mit.edu/sicp/full-text/sicp/book/node69.html


I came up with this prototype:

class Enumerator
    # return a generator for all elements from enumeration where block 
returns true
    def select &block
        Enumerator.new do |y|
            self.each do |obj|
                if block.call(obj)
                    y<<obj
                end
            end
        end
    end
end



Let's wrap an open ended Range in a Generator:
e=Enumerator.new{|y| (123..Float::INFINITY).each{|n|y<<n}}
e.select{|n|n.even?}.take(5)
=> [124, 126, 128, 130, 132]


voilà!
Posted by Fred Smith (fredsmith1981)
on 2012-06-08 07:27
(Received via mailing list)
Issue #6552 has been updated by gregolsen (Innokenty Mikhailov).


You might be interested in Enumerator::Lazy that effectively solves you 
problem.
(123..Float::INFINITY).lazy.select{|n|n.even?}.take(5).force
It's in trunk already and will be available in ruby 2.0
----------------------------------------
Feature #6552: Enumerator::Generator:select should return another 
Enumerator::Generator
https://bugs.ruby-lang.org/issues/6552#change-27087

Author: eike.rb (Eike Dierks)
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 1.9.3


The current implementation of Enumerator:select fails when applied to an 
open ended Enumerator:Generator,
resulting in an endless loop.

In the current implementation, :select seems to collect all values from 
the enumerator before applying the selection.
If that Enumeration is not bound, this results in an endless loop.

Instead, applying :select to a Generator should be applied to each 
object in turn and should itself return a Enumerator::Generator.

For example to select the first 5 even numbers starting at 123 should 
work as:
    (123..Float::INFINITY).select{|n|n.even?}.take(5)
but this currently results in an endless loop.

The same problem applies for :map and some other operators on 
Enumerations

However changing :select and :map to make them work with open ended 
Enumerations
might also change the api contract as they are currently defined to 
return an array.


We might want to have a look at the SICSP on streams,
    http://mitpress.mit.edu/sicp/full-text/sicp/book/node69.html


I came up with this prototype:

class Enumerator
    # return a generator for all elements from enumeration where block 
returns true
    def select &block
        Enumerator.new do |y|
            self.each do |obj|
                if block.call(obj)
                    y<<obj
                end
            end
        end
    end
end



Let's wrap an open ended Range in a Generator:
e=Enumerator.new{|y| (123..Float::INFINITY).each{|n|y<<n}}
e.select{|n|n.even?}.take(5)
=> [124, 126, 128, 130, 132]


voilà!
Posted by mame (Yusuke Endoh) (Guest)
on 2012-11-24 06:20
(Received via mailing list)
Issue #6552 has been updated by mame (Yusuke Endoh).

Status changed from Feedback to Rejected

I agree with gregolsen.  No feedback.  Closing.

--
Yusuke Endoh <mame@tsg.ne.jp>
----------------------------------------
Feature #6552: Enumerator::Generator:select should return another 
Enumerator::Generator
https://bugs.ruby-lang.org/issues/6552#change-33792

Author: eike.rb (Eike Dierks)
Status: Rejected
Priority: Normal
Assignee:
Category: core
Target version: 1.9.3


The current implementation of Enumerator:select fails when applied to an 
open ended Enumerator:Generator,
resulting in an endless loop.

In the current implementation, :select seems to collect all values from 
the enumerator before applying the selection.
If that Enumeration is not bound, this results in an endless loop.

Instead, applying :select to a Generator should be applied to each 
object in turn and should itself return a Enumerator::Generator.

For example to select the first 5 even numbers starting at 123 should 
work as:
    (123..Float::INFINITY).select{|n|n.even?}.take(5)
but this currently results in an endless loop.

The same problem applies for :map and some other operators on 
Enumerations

However changing :select and :map to make them work with open ended 
Enumerations
might also change the api contract as they are currently defined to 
return an array.


We might want to have a look at the SICSP on streams,
    http://mitpress.mit.edu/sicp/full-text/sicp/book/node69.html


I came up with this prototype:

class Enumerator
    # return a generator for all elements from enumeration where block 
returns true
    def select &block
        Enumerator.new do |y|
            self.each do |obj|
                if block.call(obj)
                    y<<obj
                end
            end
        end
    end
end



Let's wrap an open ended Range in a Generator:
e=Enumerator.new{|y| (123..Float::INFINITY).each{|n|y<<n}}
e.select{|n|n.even?}.take(5)
=> [124, 126, 128, 130, 132]


voilà!
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.