ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:89121] [Ruby trunk Feature#15144] Enumerator#chain
       [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
@ 2018-09-21 19:00 ` zverok.offline
  2018-09-21 22:57 ` [ruby-core:89124] " shevegen
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: zverok.offline @ 2018-09-21 19:00 UTC (permalink / raw
  To: ruby-core

Issue #15144 has been reported by zverok (Victor Shepelev).

----------------------------------------
Feature #15144: Enumerator#chain
https://bugs.ruby-lang.org/issues/15144

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I am not sure I am not missing something, but...

```ruby
[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator
```
...seem to be a useful pattern. 

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...
```ruby
# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection
```

Prototype impl. is dead simple, of course:
```ruby
class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end
```

Obviously, the effect could be reached with `flat_map`, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-core:89124] [Ruby trunk Feature#15144] Enumerator#chain
       [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
  2018-09-21 19:00 ` [ruby-core:89121] [Ruby trunk Feature#15144] Enumerator#chain zverok.offline
@ 2018-09-21 22:57 ` shevegen
  2018-10-10  6:18 ` [ruby-core:89352] " knu
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: shevegen @ 2018-09-21 22:57 UTC (permalink / raw
  To: ruby-core

Issue #15144 has been updated by shevegen (Robert A. Heiler).


> Obviously, the effect could be reached with flat_map

I always found that name weird so ... assumingly that it is the same
as .flatten.map, I always used the latter. :-)

(I don't recall flat_map offhand and I happily admit that I have not
googled; I try to keep ruby so simple to need only few things if 
possible.)

> but it seems "chaining" of iterations is pretty common and clear
> concept (and Google search for "ruby enumerator chain" shows
> people constantly ask about the way).

Well, I think this may have more to do how to name something. It may
be best to actually ask matz about the "chaining" here.

My personal opinion, which may be wrong, is that the term chaining
is used here just to put method after method onto an object (e. g.
send message after message to your object) - and have it perform
the corresponding code defined in these methods. A bit like a stream
of data through a pipe, a filter.

If this is a correct point of view (and I really don't know; we may
have to ask matz), then there should not be a need to call it
a "chain" - but most definitely to not use it as a word for a new
or additional method, be it .chain() or .chaining(). But again,
ultimately only matz knows.

By the way:

    [1, 2, 3].each.chain([3, 4, 5].each) 

The repetition of .each seems a bit awkward and the intention is
also not very clear to me. But that is just my personal opinion;
people write ruby code in very different ways. The above code 
looks alien to me too. :)

----------------------------------------
Feature #15144: Enumerator#chain
https://bugs.ruby-lang.org/issues/15144#change-74143

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I am not sure I am not missing something, but...

```ruby
[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator
```
...seem to be a useful pattern. 

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...
```ruby
# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection
```

Prototype impl. is dead simple, of course:
```ruby
class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end
```

Obviously, the effect could be reached with `flat_map`, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-core:89352] [Ruby trunk Feature#15144] Enumerator#chain
       [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
  2018-09-21 19:00 ` [ruby-core:89121] [Ruby trunk Feature#15144] Enumerator#chain zverok.offline
  2018-09-21 22:57 ` [ruby-core:89124] " shevegen
@ 2018-10-10  6:18 ` knu
  2018-11-15 21:17 ` [ruby-core:89822] [Ruby trunk Feature#15144][Assigned] Enumerator#chain knu
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: knu @ 2018-10-10  6:18 UTC (permalink / raw
  To: ruby-core

Issue #15144 has been updated by knu (Akinori MUSHA).


In today's developer meeting, Matz said Enumerator#+ would be OK to add, so I'm going to work on it first and then we'll think about an alias.

----------------------------------------
Feature #15144: Enumerator#chain
https://bugs.ruby-lang.org/issues/15144#change-74383

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
I am not sure I am not missing something, but...

```ruby
[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator
```
...seem to be a useful pattern. 

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...
```ruby
# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection
```

Prototype impl. is dead simple, of course:
```ruby
class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end
```

Obviously, the effect could be reached with `flat_map`, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-core:89822] [Ruby trunk Feature#15144][Assigned] Enumerator#chain
       [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2018-10-10  6:18 ` [ruby-core:89352] " knu
@ 2018-11-15 21:17 ` knu
  2018-11-21  6:26 ` [ruby-core:89916] [Ruby trunk Feature#15144] Enumerator#chain knu
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: knu @ 2018-11-15 21:17 UTC (permalink / raw
  To: ruby-core

Issue #15144 has been updated by knu (Akinori MUSHA).

Status changed from Open to Assigned
Assignee set to matz (Yukihiro Matsumoto)

I'm working on this and the implementation of Enumerator#+(enum) and Enumerator#chain(*enums) is about to complete.

Matz, what do you think about the name "chain"?  Python has [chain()](https://docs.python.org/3/library/itertools.html#itertools.chain), Rust too has [chain](https://doc.rust-lang.org/core/iter/trait.Iterator.html#method.chain), and I cannot think of any better name.

----------------------------------------
Feature #15144: Enumerator#chain
https://bugs.ruby-lang.org/issues/15144#change-74882

* Author: zverok (Victor Shepelev)
* Status: Assigned
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
* Target version: 
----------------------------------------
I am not sure I am not missing something, but...

```ruby
[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator
```
...seem to be a useful pattern. 

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...
```ruby
# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection
```

Prototype impl. is dead simple, of course:
```ruby
class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end
```

Obviously, the effect could be reached with `flat_map`, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).



-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-core:89916] [Ruby trunk Feature#15144] Enumerator#chain
       [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2018-11-15 21:17 ` [ruby-core:89822] [Ruby trunk Feature#15144][Assigned] Enumerator#chain knu
@ 2018-11-21  6:26 ` knu
  2018-11-21  8:10 ` [ruby-core:89918] " knu
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 8+ messages in thread
From: knu @ 2018-11-21  6:26 UTC (permalink / raw
  To: ruby-core

Issue #15144 has been updated by knu (Akinori MUSHA).

File 0001-Implement-Enumerator-Chain-and-Enumerator-chain-Feat.patch added

I've written an initial implementation as attached:

- `Enumerator.chain(*enums)` to generate an enumerator chain of `enums`
- `Enumerator#+(other)` to generate an enumerator chain of `[self, other]`
- `Enumerator#chain(*others)` to generate an enumerator chain of `[self, *others]`

Some notes:

- The constructor is currently `Enumerator::Chain.new(*enums)` but it should probably be `Enumerator::Chain.new(enums)` to make it extensible to take an enumerable in general, with `itertools.chain.from_iterable` of Python in mind.
- `Enumerator.chain(Enumerator.chain(e1, e2), e3)` cannot be optimized to `Enumerator.chain(e1, e2, e3)` because it is expected that the intermediate object `Enumerator.chain(e1, e2)` is expected to receive a call for `each` when `Enumerator.chain(Enumerator.chain(e1, e2), e3).each {…}` is called.

----------------------------------------
Feature #15144: Enumerator#chain
https://bugs.ruby-lang.org/issues/15144#change-74999

* Author: zverok (Victor Shepelev)
* Status: Assigned
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
* Target version: 
----------------------------------------
I am not sure I am not missing something, but...

```ruby
[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator
```
...seem to be a useful pattern. 

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...
```ruby
# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection
```

Prototype impl. is dead simple, of course:
```ruby
class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end
```

Obviously, the effect could be reached with `flat_map`, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).

---Files--------------------------------
0001-Implement-Enumerator-Chain-and-Enumerator-chain-Feat.patch (13.3 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-core:89918] [Ruby trunk Feature#15144] Enumerator#chain
       [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2018-11-21  6:26 ` [ruby-core:89916] [Ruby trunk Feature#15144] Enumerator#chain knu
@ 2018-11-21  8:10 ` knu
  2018-11-22  7:36 ` [ruby-core:89954] " knu
  2018-11-22  7:37 ` [ruby-core:89955] " knu
  7 siblings, 0 replies; 8+ messages in thread
From: knu @ 2018-11-21  8:10 UTC (permalink / raw
  To: ruby-core

Issue #15144 has been updated by knu (Akinori MUSHA).


knu (Akinori MUSHA) wrote:
> - The constructor is currently `Enumerator::Chain.new(*enums)` but it should probably be `Enumerator::Chain.new(enums)` to make it extensible to take an enumerable in general, with `itertools.chain.from_iterable` of Python in mind.

This could be implemented as a different class if needed, because it would have little in common with an array-based chain.

----------------------------------------
Feature #15144: Enumerator#chain
https://bugs.ruby-lang.org/issues/15144#change-75001

* Author: zverok (Victor Shepelev)
* Status: Assigned
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
* Target version: 
----------------------------------------
I am not sure I am not missing something, but...

```ruby
[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator
```
...seem to be a useful pattern. 

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...
```ruby
# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection
```

Prototype impl. is dead simple, of course:
```ruby
class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end
```

Obviously, the effect could be reached with `flat_map`, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).

---Files--------------------------------
0001-Implement-Enumerator-Chain-and-Enumerator-chain-Feat.patch (13.3 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-core:89954] [Ruby trunk Feature#15144] Enumerator#chain
       [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2018-11-21  8:10 ` [ruby-core:89918] " knu
@ 2018-11-22  7:36 ` knu
  2018-11-22  7:37 ` [ruby-core:89955] " knu
  7 siblings, 0 replies; 8+ messages in thread
From: knu @ 2018-11-22  7:36 UTC (permalink / raw
  To: ruby-core

Issue #15144 has been updated by knu (Akinori MUSHA).


We got Matz's approval for adding Enumerable#chain (instead of Enumerator#chain) and Enumerator#+.

----------------------------------------
Feature #15144: Enumerator#chain
https://bugs.ruby-lang.org/issues/15144#change-75051

* Author: zverok (Victor Shepelev)
* Status: Assigned
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
* Target version: 
----------------------------------------
I am not sure I am not missing something, but...

```ruby
[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator
```
...seem to be a useful pattern. 

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...
```ruby
# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection
```

Prototype impl. is dead simple, of course:
```ruby
class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end
```

Obviously, the effect could be reached with `flat_map`, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).

---Files--------------------------------
0001-Implement-Enumerator-Chain-and-Enumerator-chain-Feat.patch (13.3 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [ruby-core:89955] [Ruby trunk Feature#15144] Enumerator#chain
       [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
                   ` (6 preceding siblings ...)
  2018-11-22  7:36 ` [ruby-core:89954] " knu
@ 2018-11-22  7:37 ` knu
  7 siblings, 0 replies; 8+ messages in thread
From: knu @ 2018-11-22  7:37 UTC (permalink / raw
  To: ruby-core

Issue #15144 has been updated by knu (Akinori MUSHA).

Assignee changed from matz (Yukihiro Matsumoto) to knu (Akinori MUSHA)

----------------------------------------
Feature #15144: Enumerator#chain
https://bugs.ruby-lang.org/issues/15144#change-75052

* Author: zverok (Victor Shepelev)
* Status: Assigned
* Priority: Normal
* Assignee: knu (Akinori MUSHA)
* Target version: 
----------------------------------------
I am not sure I am not missing something, but...

```ruby
[1, 2, 3].each.chain([3, 4, 5].each) # => Enumerator
```
...seem to be a useful pattern. 

It especially shows itself in case of lazy enumerators, representing several long-calculated sequences, like something...
```ruby
# just data from several sources, abstracted into enumerator, fetching it on demand
process = URLS.lazy.map(&Faraday.method(:get)))
  .chain(LOCAL_FILES.lazy.map(&File.method(:read)))
  .chain(FALLBACK_FILE.then.lazy.map(&File.method(:read))) # with yield_self aka then we can even chain ONE value

process.detect { |val| found?(val) } # uniformely search several sources (lazy-loading them) for some value

# tty-progressbar is able to work with enumerables:
bar = TTY::ProgressBar.new("[:bar]", total: URLS.count + LOCAL_FILES.count + 1)
bar.iterate(process).detect { |val| found?(val) } # shows progress-bar for uniform process of detection
```

Prototype impl. is dead simple, of course:
```ruby
class Enumerator
  def chain(*others)
    Enumerator.new { |y|
      [self, *others].each { |e| e.each { |v| y << v } }
    }
  end
end
```

Obviously, the effect could be reached with `flat_map`, but it seems "chaining" of iterations is pretty common and clear concept (and Google search for "ruby enumerator chain" shows people constantly ask about the way).

---Files--------------------------------
0001-Implement-Enumerator-Chain-and-Enumerator-chain-Feat.patch (13.3 KB)


-- 
https://bugs.ruby-lang.org/

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2018-11-22  7:37 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <redmine.issue-15144.20180921190023@ruby-lang.org>
2018-09-21 19:00 ` [ruby-core:89121] [Ruby trunk Feature#15144] Enumerator#chain zverok.offline
2018-09-21 22:57 ` [ruby-core:89124] " shevegen
2018-10-10  6:18 ` [ruby-core:89352] " knu
2018-11-15 21:17 ` [ruby-core:89822] [Ruby trunk Feature#15144][Assigned] Enumerator#chain knu
2018-11-21  6:26 ` [ruby-core:89916] [Ruby trunk Feature#15144] Enumerator#chain knu
2018-11-21  8:10 ` [ruby-core:89918] " knu
2018-11-22  7:36 ` [ruby-core:89954] " knu
2018-11-22  7:37 ` [ruby-core:89955] " knu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).