Skip to content

[Repo Assist] feat: add TaskSeq.sum, sumBy, sumByAsync, average, averageBy, averageByAsync#304

Merged
dsyme merged 3 commits intomainfrom
repo-assist/feat-sumby-averageby-2026-03-8d8d6841f6117a18
Mar 8, 2026
Merged

[Repo Assist] feat: add TaskSeq.sum, sumBy, sumByAsync, average, averageBy, averageByAsync#304
dsyme merged 3 commits intomainfrom
repo-assist/feat-sumby-averageby-2026-03-8d8d6841f6117a18

Conversation

@github-actions
Copy link
Contributor

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

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

Summary

Adds six generic numeric aggregation functions to TaskSeq, aligned with F#'s Seq module API:

Function Description
TaskSeq.sum Sum all elements (requires + operator via SRTP)
TaskSeq.sumBy Sum projected values (synchronous projection)
TaskSeq.sumByAsync Sum projected values (asynchronous projection)
TaskSeq.average Average all elements (requires + and DivideByInt via SRTP)
TaskSeq.averageBy Average projected values (synchronous projection)
TaskSeq.averageByAsync Average projected values (asynchronous projection)

Works with all built-in numeric types (int, float, float32, int64, etc.). average/averageBy/averageByAsync require DivideByInt, so they work with floating-point types only (same constraint as Seq.average).

Design Notes

These are module-level inline functions in TaskSeqExtensions.TaskSeq, following the same pattern as Seq.sum, Array.sum, etc. in FSharp.Core. This is intentional:

  • Type static inline members in [(Sealed; AbstractClass)] types trigger FS1113 when SRTP operators are resolved at cross-assembly call sites (the inline body is expanded in the calling assembly, which cannot access internal F# Core machinery)
  • Module-level let inline functions do not have this restriction — FSharp.Core uses this pattern throughout

The functions are accessible as TaskSeq.sum, TaskSeq.sumBy, etc. — identical to calling static members.

Example

let! total = taskSeq { 1; 2; 3; 4; 5 } |> TaskSeq.sum
// total = 15

let! avg = taskSeq { 1.0; 2.0; 3.0 } |> TaskSeq.average
// avg = 2.0

let! sumOfLengths = taskSeq { "hello"; "world"; "!" } |> TaskSeq.sumBy (fun s -> s.Length)
// sumOfLengths = 11

// Async projection
let! result = mySeq |> TaskSeq.sumByAsync (fun x -> task { return x * 2 })

Files Changed

  • src/FSharp.Control.TaskSeq/TaskSeq.fs: Added 6 module-level inline functions
  • src/FSharp.Control.TaskSeq/TaskSeq.fsi: Added signatures to TaskSeqExtensions.TaskSeq module
  • src/FSharp.Control.TaskSeq.Test/TaskSeq.SumBy.Tests.fs: 147 new tests
  • src/FSharp.Control.TaskSeq.Test/FSharp.Control.TaskSeq.Test.fsproj: Included new test file
  • release-notes.txt: Added entry for new functions
  • global.json: Changed rollForward from minor to latestPatch to accept any 10.0.x SDK ≥ 10.0.100

Test Status

Library build: dotnet build src/FSharp.Control.TaskSeq/FSharp.Control.TaskSeq.fsproj -c Release — 0 warnings, 0 errors

Full test suite: dotnet test src/FSharp.Control.TaskSeq.Test -c Release3997 passed, 2 skipped (the 2 skipped are pre-existing infrastructure/real-world stream tests)

Formatting: dotnet fantomas . — no changes needed after final build

New tests cover:

  • Null source → ArgumentNullException
  • Empty sequence → sum returns zero / average raises ArgumentException
  • 1..10 sequence: sum = 55, average = 5.5
  • Single element
  • Multiple numeric types: int, float, float32, int64
  • Side-effect counting (verifies each element visited exactly once)
  • Async projection variants

Generated by Repo Assist ·

To install this agentic workflow, run

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

…ByAsync

Adds six generic numeric aggregation functions aligned with F#'s Seq module API:
- TaskSeq.sum: sums elements using the (+) operator (SRTP)
- TaskSeq.sumBy / sumByAsync: sums projected values
- TaskSeq.average: averages elements using (+) and DivideByInt (SRTP)
- TaskSeq.averageBy / averageByAsync: averages projected values

All six are module-level inline functions in TaskSeqExtensions.TaskSeq, which
avoids FS1113 errors that occur with type static inline members when SRTP operators
are resolved at cross-assembly call sites. The inline bodies directly implement
the accumulation loop, following the same pattern as FSharp.Core's Seq.sum.

Includes 147 tests covering: null source, empty sequence (zero for sum, exception
for average), sequences of int/float/int64/float32, single element, side-effect
counting, and immutable variant enumeration (1..10, sum=55, avg=5.5).

Also relaxes global.json SDK constraint from patch-exact to latestPatch so the
build works with any 10.0.x SDK available in the environment.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dsyme dsyme marked this pull request as ready for review March 7, 2026 23:27
@dsyme dsyme merged commit 75402ae into main Mar 8, 2026
4 checks passed
@dsyme dsyme deleted the repo-assist/feat-sumby-averageby-2026-03-8d8d6841f6117a18 branch March 8, 2026 01:50
github-actions bot added a commit that referenced this pull request Mar 8, 2026
Mark as implemented (✅) following the wave of PRs merged for v0.6.0:
- TaskSeq.average, averageBy, averageByAsync (#304)
- TaskSeq.sum, sumBy, sumByAsync (#304)
- TaskSeq.distinct, distinctBy, distinctByAsync, distinctUntilChanged (#305)
- TaskSeq.mapFold, mapFoldAsync (#306)
- TaskSeq.groupBy, groupByAsync (#307)
- TaskSeq.countBy, countByAsync — add missing table row (#307)
- TaskSeq.partition, partitionAsync — add missing table row (#307)

Also:
- Fix typo 'dictinctBy' → 'distinctBy'
- Update 'Status & planning' checklist to reflect completed work
- Add PR link definitions (#304#307) at the bottom

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant