Issue #17016 has been updated by duerst (Martin D=FCrst).


parker (Parker Finch) wrote in #note-21:
> nobu (Nobuyoshi Nakada) wrote in #note-20:
> > ```ruby
> > (1..).lazy.inject(0, :+).first(10) #=3D> [0, 1, 3, 6, 10, 15, 21, 28, 3=
6, 45]
> > ```

> I'm worried about the backwards compatibility of changing the behavior of=
 `#inject` on lazy enumerables. Since right now `[1,2,3].lazy.inject(:+) # =
=3D> 6` I think it would be breaking to change that behavior to be `[1,2,3]=
.lazy.inject(:+) # =3D> #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:=
inject>`.
> =

> I'm also worried about `#inject` having different behavior for strict and=
 lazy enumerables. I don't think it would be good to have `[1,2,3].inject(:=
+)` be different than `[1,2,3].lazy.inject(:+).force`.

I fully agree. Lazy variants of methods should only differ with respect to =
laziness, not anything else.


----------------------------------------
Feature #17016: Enumerable#scan_left
https://bugs.ruby-lang.org/issues/17016#change-86722

* Author: parker (Parker Finch)
* Status: Open
* Priority: Normal
----------------------------------------
## Proposal

Add a `#scan_left` method to `Enumerable`.

(The name "scan_left" is based on Scala's scanLeft and Haskell's scanl. It =
seems like "scan_left" would be a ruby-ish name for  this concept, but I'm =
curious if there are other thoughts on naming here!)

## Background

`#scan_left` is similar to `#inject`, but it accumulates the partial result=
s that are computed. As a comparison:
```
[1, 2, 3].inject(0, &:+) =3D> 6
[1, 2, 3].scan_left(0, &:+) =3D> [0, 1, 3, 6]
```

Notably, the `scan_left` operation can be done lazily since it doesn't requ=
ire processing the entire collection before computing a value.

I recently described `#scan_left`, and its relationship to `#inject`, more =
thoroughly in [this blog post](https://medium.com/building-panorama-educati=
on/scan-left-a-lazy-incremental-alternative-to-inject-f6e946f74c00).

## Reasoning
We heavily rely on the scan operation. We use an [event-sourcing](https://m=
artinfowler.com/eaaDev/EventSourcing.html) pattern, which means that we are=
 scanning over individual "events" and building up the corresponding state.=
 We rely on the history of states and need to do this lazily (we stream eve=
nts because they cannot fit in memory). Thus the scan operation is much mor=
e applicable than the inject operation.

We suspect that there are many applications that could leverage the scan op=
eration. [This question](https://stackoverflow.com/questions/1475808/cumula=
tive-array-sum-in-ruby) would be more easily answered by `#scan_left`. It i=
s a natural fit for any application that needs to store the incrementally-c=
omputed values of an `#inject`, and a requirement for an application that n=
eeds to use `#inject` while maintaining laziness.

## Implementation
There is a Ruby implementation of this functionality [here](https://github.=
com/panorama-ed/scan_left/) and an implementation in C [here](https://githu=
b.com/ruby/ruby/pull/3078).

## Counterarguments
Introducing a new public method is committing to maintenance going forward =
and expands the size of the Ruby codebase -- it should not be done lightly.=
 I think that providing the functionality here is worth the tradeoff, but I=
 understand any hesitation to add yet more to Ruby!

---Files--------------------------------
scan_left_example.rb (2.93 KB)


-- =

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

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>