Skip to content

[Repo Assist] Add AsyncSeq.tryFindBack, findBack, tryFindBackAsync, findBackAsync#289

Closed
github-actions[bot] wants to merge 2 commits intomainfrom
repo-assist/improve-findback-2026-03-25-ec3fab6e9f97deef
Closed

[Repo Assist] Add AsyncSeq.tryFindBack, findBack, tryFindBackAsync, findBackAsync#289
github-actions[bot] wants to merge 2 commits intomainfrom
repo-assist/improve-findback-2026-03-25-ec3fab6e9f97deef

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

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

Summary

Adds four backward-search functions that mirror the F# standard library Seq module:

Function Signature Description
tryFindBack ('T -> bool) -> AsyncSeq<'T> -> Async<'T option> Returns the last element matching a sync predicate, or None
findBack ('T -> bool) -> AsyncSeq<'T> -> Async<'T> Like above, but raises KeyNotFoundException on no match
tryFindBackAsync ('T -> Async(bool)) -> AsyncSeq<'T> -> Async<'T option> Async-predicate variant of tryFindBack
findBackAsync ('T -> Async(bool)) -> AsyncSeq<'T> -> Async<'T> Async-predicate variant of findBack

Motivation

AsyncSeq already has tryFind / find (return the first match). The complementary backward variants — present in Seq.tryFindBack / Seq.findBack since F# 4.0 — were missing. These are useful for scanning time-ordered sequences or event logs where the most recent matching record is needed.

Implementation

tryFindBackAsync is the primitive: it iterates the entire sequence, overwriting result whenever the predicate holds, and returns the final value. The other three functions are simple wrappers.

let tryFindBackAsync (predicate: 'T -> Async(bool)) (source: AsyncSeq<'T>) : Async<'T option> = async {
    use ie = source.GetEnumerator()
    let! move = ie.MoveNext()
    let mutable b = move
    let mutable result = None
    while b.IsSome do
      let! ok = predicate b.Value
      if ok then result <- b
      let! next = ie.MoveNext()
      b <- next
    return result }

Changes

  • src/FSharp.Control.AsyncSeq/AsyncSeq.fs — 4 new function implementations
  • src/FSharp.Control.AsyncSeq/AsyncSeq.fsi — 4 new public signatures with XML-doc
  • tests/FSharp.Control.AsyncSeq.Tests/AsyncSeqTests.fs — 10 new tests
  • RELEASE_NOTES.md — added to 4.11.0 entry

New Tests

Test What it checks
tryFindBack returns last matching element Returns Some 6 from [1;3;5;2;4;6;7] with even predicate
tryFindBack returns None when no element matches All-odd sequence → None
tryFindBack returns None for empty sequence Empty → None
tryFindBack returns last element when all match Always-true predicate → last element
findBack returns last matching element Returns last even from mixed sequence
findBack raises KeyNotFoundException when no match No even in all-odd → exception
tryFindBackAsync returns last element satisfying async predicate x < 4Some 3
tryFindBackAsync returns None when nothing matches x > 99None
findBackAsync returns last element satisfying async predicate x % 2 = 0 → last even
findBackAsync raises KeyNotFoundException when no match x > 99 → exception

Test Status

✅ Build succeeded (pre-existing OOM on netstandard2.1 full-solution build — infrastructure limitation, not caused by this change).

✅ All 358/358 tests pass (dotnet test tests/FSharp.Control.AsyncSeq.Tests/...).

Generated by Repo Assist ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@4957663821dbb3260348084fa2f1659701950fef

Add four backward-search functions that mirror F# standard library:

  - tryFindBack    : ('T -> bool) -> AsyncSeq<'T> -> Async<'T option>
  - findBack       : ('T -> bool) -> AsyncSeq<'T> -> Async<'T>
  - tryFindBackAsync : ('T -> Async<bool>) -> AsyncSeq<'T> -> Async<'T option>
  - findBackAsync  : ('T -> Async<bool>) -> AsyncSeq<'T> -> Async<'T>

These iterate the entire source sequence and return the last element
satisfying the predicate, complementing the existing tryFind / find
(which return the first match). findBack raises KeyNotFoundException
when no element satisfies the predicate; tryFindBack returns None.

All four are documented in AsyncSeq.fsi. 10 new tests added; all
358/358 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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