Skip to content

Commit e9c947b

Browse files
committed
Implement TaskSeq.forall and forallAsync
1 parent 38dce91 commit e9c947b

File tree

3 files changed

+67
-4
lines changed

3 files changed

+67
-4
lines changed

src/FSharp.Control.TaskSeq/TaskSeq.fs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,9 @@ type TaskSeq private () =
358358
static member except itemsToExclude source = Internal.except itemsToExclude source
359359
static member exceptOfSeq itemsToExclude source = Internal.exceptOfSeq itemsToExclude source
360360

361+
static member forall predicate source = Internal.forall (Predicate predicate) source
362+
static member forallAsync predicate source = Internal.forall (PredicateAsync predicate) source
363+
361364
static member exists predicate source =
362365
Internal.tryFind (Predicate predicate) source
363366
|> Task.map Option.isSome

src/FSharp.Control.TaskSeq/TaskSeq.fsi

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,30 @@ type TaskSeq =
875875
/// <exception cref="T:ArgumentNullException">Thrown when the input task sequence is null.</exception>
876876
static member whereAsync: predicate: ('T -> #Task<bool>) -> source: TaskSeq<'T> -> TaskSeq<'T>
877877

878+
/// <summary>
879+
/// Tests if all elements of the sequence satisfy the given predicate. Stops evaluating
880+
/// as soon as <paramref name="predicate" /> returns <see cref="false" />.
881+
/// If <paramref name="predicate" /> is asynchronous, consider using <see cref="TaskSeq.forallAsync" />.
882+
/// </summary>
883+
///
884+
/// <param name="predicate">A function to test an element of the input sequence.</param>
885+
/// <param name="source">The input task sequence.</param>
886+
/// <returns>A task that, after awaiting, holds true if every element of the sequence satisfies the predicate; false otherwise.</returns>
887+
/// <exception cref="T:ArgumentNullException">Thrown when the input task sequence is null.</exception>
888+
static member forall: predicate: ('T -> bool) -> source: TaskSeq<'T> -> Task<bool>
889+
890+
/// <summary>
891+
/// Tests if all elements of the sequence satisfy the given asynchronous predicate. Stops evaluating
892+
/// as soon as <paramref name="predicate" /> returns <see cref="false" />.
893+
/// If <paramref name="predicate" /> is synchronous, consider using <see cref="TaskSeq.forall" />.
894+
/// </summary>
895+
///
896+
/// <param name="predicate">A function to test an element of the input sequence.</param>
897+
/// <param name="source">The input task sequence.</param>
898+
/// <returns>A task that, after awaiting, holds true if every element of the sequence satisfies the predicate; false otherwise.</returns>
899+
/// <exception cref="T:ArgumentNullException">Thrown when the input task sequence is null.</exception>
900+
static member forallAsync: predicate: ('T -> #Task<bool>) -> source: TaskSeq<'T> -> Task<bool>
901+
878902
/// <summary>
879903
/// Returns a task sequence that, when iterated, skips <paramref name="count" /> elements of the underlying
880904
/// sequence, and then yields the remainder. Raises an exception if there are not <paramref name="count" />

src/FSharp.Control.TaskSeq/TaskSeqInternal.fs

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -690,18 +690,54 @@ module internal TaskSeqInternal =
690690

691691
taskSeq {
692692
match predicate with
693-
| Predicate predicate ->
693+
| Predicate syncPredicate ->
694694
for item in source do
695-
if predicate item then
695+
if syncPredicate item then
696696
yield item
697697

698-
| PredicateAsync predicate ->
698+
| PredicateAsync asyncPredicate ->
699699
for item in source do
700-
match! predicate item with
700+
match! asyncPredicate item with
701701
| true -> yield item
702702
| false -> ()
703703
}
704704

705+
let forall predicate (source: TaskSeq<_>) =
706+
checkNonNull (nameof source) source
707+
708+
match predicate with
709+
| Predicate syncPredicate -> task {
710+
use e = source.GetAsyncEnumerator CancellationToken.None
711+
let mutable state = true
712+
let! cont = e.MoveNextAsync()
713+
let mutable hasMore = cont
714+
715+
while state && hasMore do
716+
state <- syncPredicate e.Current
717+
718+
if state then
719+
let! cont = e.MoveNextAsync()
720+
hasMore <- cont
721+
722+
return state
723+
}
724+
725+
| PredicateAsync asyncPredicate -> task {
726+
use e = source.GetAsyncEnumerator CancellationToken.None
727+
let mutable state = true
728+
let! cont = e.MoveNextAsync()
729+
let mutable hasMore = cont
730+
731+
while state && hasMore do
732+
let! pred = asyncPredicate e.Current
733+
state <- pred
734+
735+
if state then
736+
let! cont = e.MoveNextAsync()
737+
hasMore <- cont
738+
739+
return state
740+
}
705741

706742
let skipOrTake skipOrTake count (source: TaskSeq<_>) =
707743
checkNonNull (nameof source) source

0 commit comments

Comments
 (0)