scan — Evolution of State Along the Timeline
scan
is one of the most powerful primitives in this library. It serves as the fundamental tool for constructing a timeline that has “state” which evolves over time.
The Three Dimensions of Folding: Structure and Time
Section titled “The Three Dimensions of Folding: Structure and Time”To understand the unique role of scan
, we will compare three types of “folds” in programming. The first two deal with Structure, while the third, scan
, deals with a completely different dimension: Time.
fold
(Folding of Structure): Deals with a static collection structure like[1, 2, 3]
and calculates one final value (e.g.,6
).foldTimelines
(Folding of Structure): Deals with a list of timelines (a dynamic collection structure) like[Timeline<1>, Timeline<2>, Timeline<3>]
and combines them into one resulting timeline.scan
(Folding of Time): Deals with a single timeline (a temporal event stream) like1 -> 2 -> 3
and, each time an event occurs, generates a new timeline that holds the intermediate values (e.g.,1 -> 3 -> 6
).
The following comparison table summarizes these differences.
Feature | fold (Structure) | foldTimelines (Structure) | scan (Time) |
---|---|---|---|
Purpose | Final aggregation | Structural composition | Temporal aggregation |
Input | Array, etc. | List of timelines | One timeline |
Processing | All at once | All at once | Each time an event occurs |
Output | One final value | Timeline of the final result | Timeline of intermediate progress |
Analogy | Total amount in a shopping cart 🧾 | Final tally of multiple votes 🗳️ | Account balance history 📈 |
fold
and foldTimelines
are very similar in that they both combine an input “collection structure” into one. On the other hand, this comparison makes it clear that scan
is a tool with a completely different purpose: to track the temporal changes of a single stream. It is the core operation for constructing a stateful timeline that remembers its past history and updates its state based on new inputs.
API Definition
Section titled “API Definition”F#: scan: ('state -> 'input -> 'state) -> 'state -> Timeline<'input> -> Timeline<'state>
Section titled “F#: scan: ('state -> 'input -> 'state) -> 'state -> Timeline<'input> -> Timeline<'state>”Note: In F#, scan
is a standalone function.
TS: .scan<S>(accumulator: (acc: S, value: T) => S, seed: S): Timeline<S>
Section titled “TS: .scan<S>(accumulator: (acc: S, value: T) => S, seed: S): Timeline<S>”Code Example in TypeScript
Section titled “Code Example in TypeScript”Let’s look at the behavior of scan
with a counter that sums up incoming numbers.
// Create a timeline of numbersconst numberStream = Timeline<number>(0);
// Use scan to sum up the incoming numbersconst runningTotal = numberStream.scan( (sum, currentValue) => sum + currentValue, // accumulator: add the new value to the current sum 0 // seed: the initial value of the sum);
// runningTotal always holds the latest totalconsole.log(runningTotal.at(Now)); // 0
numberStream.define(Now, 5);console.log(runningTotal.at(Now)); // 5 (0 + 5)
numberStream.define(Now, 10);console.log(runningTotal.at(Now)); // 15 (5 + 10)
numberStream.define(Now, -3);console.log(runningTotal.at(Now)); // 12 (15 - 3)
Canvas Demo (Placeholder)
Section titled “Canvas Demo (Placeholder)”A demo that visualizes how the state timeline (the total sum) constructed by scan
is updated in real-time each time a number flows into the input timeline.