Skip to content

[Repo Assist] Add AsyncSeq.mapFold, mapFoldAsync, allPairs, rev#266

Merged
dsyme merged 4 commits intomainfrom
repo-assist/improve-new-combinators-87b33ebcb712bf81
Mar 8, 2026
Merged

[Repo Assist] Add AsyncSeq.mapFold, mapFoldAsync, allPairs, rev#266
dsyme merged 4 commits intomainfrom
repo-assist/improve-new-combinators-87b33ebcb712bf81

Conversation

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented Mar 4, 2026

🤖 This PR was created by Repo Assist, an automated AI assistant.

Summary

Adds four new Seq-mirroring combinators to fill gaps in the AsyncSeq API:

New function Mirrors Description
AsyncSeq.mapFoldAsync Seq.mapFold Maps each element with an async folder that also threads an accumulator state; returns Async<'Result array * 'State>
AsyncSeq.mapFold Seq.mapFold Synchronous variant of mapFoldAsync
AsyncSeq.allPairs Seq.allPairs Cartesian product of two async sequences; second source is fully buffered before iteration begins
AsyncSeq.rev Seq.rev Reverses an async sequence; entire source is buffered first

Usage Examples

// mapFold: number elements and accumulate a running total
let results, total =
    AsyncSeq.mapFold (fun acc x -> (string x, acc + x)) 0 source
    |> Async.RunSynchronously
// results: [| "1"; "2"; "3" |], total: 6

// allPairs: cartesian product
let pairs =
    AsyncSeq.allPairs (asyncSeq { yield 1; yield 2 }) (asyncSeq { yield 'a'; yield 'b' })
    |> AsyncSeq.toArrayAsync |> Async.RunSynchronously
// [| (1,'a'); (1,'b'); (2,'a'); (2,'b') |]

// rev: reverse
let reversed =
    AsyncSeq.rev (asyncSeq { yield 1; yield 2; yield 3 })
    |> AsyncSeq.toArrayAsync |> Async.RunSynchronously
// [| 3; 2; 1 |]
```

## Implementation Notes

- **`mapFoldAsync`/`mapFold`**: placed after `reduceAsync`/`reduce` in the source, uses the same internal enumerator pattern as other aggregators
- **`allPairs`**: placed after `zipWith3`; buffers `source2` using a `List<'T2>` (can't call `toArrayAsync` at that position in the file since it's defined later), then iterates `source1`
- **`rev`**: placed after `sortWith` (inside `#if !FABLE_COMPILER`); buffers to array via `toArrayAsync` then yields in reverse

## Test Status

✅ All **297 tests pass** (287 pre-existing + **10 new tests** covering success cases, empty inputs, and edge cases for all four new functions).

```
Passed!  - Failed: 0, Passed: 297, Skipped: 0, Total: 297

Generated by Repo Assist ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@10f087607af87e4e89439161f1e5d4724235f396

Four new Seq-mirroring combinators:
- mapFoldAsync: maps elements with an async folder that threads state,
  returns (results array, final state); mirrors Seq.mapFold
- mapFold: synchronous variant of mapFoldAsync
- allPairs: cartesian product of two async sequences; buffers second
  source before iteration; mirrors Seq.allPairs
- rev: reverses an async sequence; buffers entire source; mirrors Seq.rev

All 297 tests pass (10 new tests added).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dsyme added 2 commits March 7, 2026 19:02
Updated release notes for version 4.8.0, adding new features and improvements.
@dsyme dsyme marked this pull request as ready for review March 7, 2026 19:03
@dsyme dsyme merged commit 6a8cf8b into main Mar 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant