Issue #17016 has been updated by parker (Parker Finch).

File scan_left_example.rb added

> The name `scan` seems confusing at least, since it has nothing to do with `String#scan`.
> And `*_left` has no precedent in Ruby.
> 
> It seems it's basically recording the history of each block call (+ the initial value), maybe a name expressing that would be good.

Ah sorry, I forgot to mention that the term "scan" is what this operation is typically called in functional programming (see [here](https://en.wikipedia.org/wiki/Prefix_sum#Scan_higher_order_function) for a quick overview). So that's how the name is derived. I agree that the `*_left` suffix doesn't sound very Ruby-ish, maybe just `#scan` would be better. But then we *really* have a conflict with the name of `String#scan`, thanks for pointing that out! Any thoughts on what this could be called to disambiguate that? Perhaps `#accumulate`?

> Do you have real-world usages you can show?

The most significant real-world usage that I've had it for is the one I briefly described above. The "scan" operation is a very good fit when processing streams of data changes. To really concretize it, our use case is in education data. One example is that each day we see if a student is present or absent. We use a scan over that data to count the number of absences that a student has -- a fold (i.e. `#inject` or `#reduce`) would be insufficient because the stream is lazy.

To get a small, self-contained example, I wrote up a script that uses it (and shows how other implementations of the behavior could work). That is attached, let me know if there's anything else I can do to show the usefulness here!

> It seems kind of niche (seems expensive if the collection is large) and can easily be replaced by `each` + 2 variables (if not lazy at least).

I don't think it's actually that niche! A lot of array algorithms become easier with a `scan` operation, see [this post](https://medium.com/beauty-date-stories/algorithms-how-prefix-sums-can-help-improving-operations-over-arrays-b1f8e8141668) for an example. And I don't think that it's particularly expensive -- it should be similar in cost to a `map`.

In fact, scan-like behavior (with laziness) can be implemented with `map` without *too* much trouble. ([This](https://github.com/panorama-ed/scan_left/blob/029d3ac4fa2073afa9d7da5d7932992849c235f2/lib/scan_left.rb#L49) is the heart of the ruby implementation.) But assigning to a variable inside of the block passed to `map` doesn't feel very Ruby-ish to me:
```ruby
val = 0
collection.map { |x| val = val + x }
```
feels less natural than something like
```ruby
collection.scan(&:+)
```

One of my favorite aspects of Ruby is how easy it is to write in a functional programming style, and including the `scan` operation would expand the number of use cases covered by functional methods.

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

* 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 results that are computed. As a comparison:
```
[1, 2, 3].inject(0, &:+) => 6
[1, 2, 3].scan_left(0, &:+) => [0, 1, 3, 6]
```

Notably, the `scan_left` operation can be done lazily since it doesn't require 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-education/scan-left-a-lazy-incremental-alternative-to-inject-f6e946f74c00).

## Reasoning
We heavily rely on the scan operation. We use an [event-sourcing](https://martinfowler.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 events because they cannot fit in memory). Thus the scan operation is much more applicable than the inject operation.

We suspect that there are many applications that could leverage the scan operation. [This question](https://stackoverflow.com/questions/1475808/cumulative-array-sum-in-ruby) would be more easily answered by `#scan_left`. It is a natural fit for any application that needs to store the incrementally-computed values of an `#inject`, and a requirement for an application that needs 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://github.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=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>