@@ -7,6 +7,7 @@ namespace FSharpx.Control
77open System
88open System.Threading
99open System.IO
10+ open FSharpx.Control .Utils
1011
1112// ----------------------------------------------------------------------------
1213
@@ -34,6 +35,17 @@ module AsyncSeq =
3435 /// Creates an asynchronous sequence that generates a single element and then ends
3536 let singleton ( v : 'T ) : AsyncSeq < 'T > =
3637 async { return Cons( v, empty) }
38+
39+ /// Generates an async sequence using the specified generator function.
40+ let rec unfoldAsync ( f : 'State -> Async <( 'T * 'State ) option >) ( s : 'State ) : AsyncSeq < 'T > =
41+ f s
42+ |> Async.map ( function
43+ | Some ( a, s) -> Cons( a, unfoldAsync f s)
44+ | None -> Nil)
45+
46+ /// Creates an async sequence which repeats the specified value indefinitely.
47+ let rec replicate ( v : 'T ) : AsyncSeq < 'T > =
48+ Cons( v, async.Delay <| fun () -> replicate v) |> async.Return
3749
3850 /// Yields all elements of the first asynchronous sequence and then
3951 /// all elements of the second asynchronous sequence.
@@ -413,8 +425,19 @@ module AsyncSeq =
413425
414426 // --------------------------------------------------------------------------
415427
428+ /// Threads a state through the mapping over an async sequence using an async function.
429+ let rec threadStateAsync ( f : 's -> 'a -> Async < 'b * 's >) ( st : 's ) ( s : AsyncSeq < 'a >) : AsyncSeq < 'b > = asyncSeq {
430+ let! s = s
431+ match s with
432+ | Nil -> ()
433+ | Cons( a, tl) ->
434+ let! b , st' = f st a
435+ yield b
436+ yield ! threadStateAsync f st' tl }
437+
416438 /// Combines two asynchronous sequences into a sequence of pairs.
417439 /// The values from sequences are retrieved in parallel.
440+ /// The resulting sequence stops when either of the argument sequences stop.
418441 let rec zip ( input1 : AsyncSeq < 'T1 >) ( input2 : AsyncSeq < 'T2 >) : AsyncSeq < _ > = async {
419442 let! ft = input1 |> Async.StartChild
420443 let! s = input2
@@ -424,6 +447,65 @@ module AsyncSeq =
424447 return Cons( ( hf, hs), zip tf ts)
425448 | _ -> return Nil }
426449
450+ /// Combines two asynchronous sequences using the specified function.
451+ /// The values from sequences are retrieved in parallel.
452+ /// The resulting sequence stops when either of the argument sequences stop.
453+ let rec zipWithAsync ( z : 'a -> 'b -> Async < 'c >) ( a : AsyncSeq < 'a >) ( b : AsyncSeq < 'b >) : AsyncSeq < 'c > = async {
454+ let! a , b = Async.Parallel( a, b)
455+ match a, b with
456+ | Cons( a, atl), Cons( b, btl) ->
457+ let! c = z a b
458+ return Cons( c, zipWithAsync z atl btl)
459+ | _ -> return Nil }
460+
461+ /// Combines two asynchronous sequences using the specified function.
462+ /// The values from sequences are retrieved in parallel.
463+ /// The resulting sequence stops when either of the argument sequences stop.
464+ let inline zipWith ( z : 'a -> 'b -> 'c ) ( a : AsyncSeq < 'a >) ( b : AsyncSeq < 'b >) : AsyncSeq < 'c > =
465+ zipWithAsync ( fun a b -> z a b |> async.Return) a b
466+
467+ /// Combines two asynchronous sequences using the specified function to which it also passes the index.
468+ /// The values from sequences are retrieved in parallel.
469+ /// The resulting sequence stops when either of the argument sequences stop.
470+ let inline zipWithIndexAsync ( f : int -> 'a -> Async < 'b >) ( s : AsyncSeq < 'a >) : AsyncSeq < 'b > =
471+ threadStateAsync ( fun i a -> f i a |> Async.map ( fun b -> b, i + 1 )) 0 s
472+
473+ /// Feeds an async sequence of values into an async sequence of async functions.
474+ let inline zappAsync ( fs : AsyncSeq < 'a -> Async < 'b >>) ( s : AsyncSeq < 'a >) : AsyncSeq < 'b > =
475+ zipWithAsync ((|>)) s fs
476+
477+ /// Feeds an async sequence of values into an async sequence of functions.
478+ let inline zapp ( fs : AsyncSeq < 'a -> 'b >) ( s : AsyncSeq < 'a >) : AsyncSeq < 'b > =
479+ zipWith ((|>)) s fs
480+
481+ /// Traverses an async sequence an applies to specified function such that if None is returned the traversal short-circuits
482+ /// and None is returned as the result. Otherwise, the entire sequence is traversed and the result returned as Some.
483+ let rec traverseOptionAsync ( f : 'a -> Async < 'b option >) ( s : AsyncSeq < 'a >) : Async < AsyncSeq < 'b > option > = async {
484+ let! s = s
485+ match s with
486+ | Nil -> return Some ( Nil |> async.Return)
487+ | Cons( a, tl) ->
488+ let! b = f a
489+ match b with
490+ | Some b ->
491+ return ! traverseOptionAsync f tl |> Async.map ( Option.map ( fun tl -> Cons( b, tl) |> async.Return))
492+ | None ->
493+ return None }
494+
495+ /// Traverses an async sequence an applies to specified function such that if Choice2Of2 is returned the traversal short-circuits
496+ /// and Choice2Of2 is returned as the result. Otherwise, the entire sequence is traversed and the result returned as Choice1Of2.
497+ let rec traverseChoiceAsync ( f : 'a -> Async < Choice < 'b , 'e >>) ( s : AsyncSeq < 'a >) : Async < Choice < AsyncSeq < 'b >, 'e >> = async {
498+ let! s = s
499+ match s with
500+ | Nil -> return Choice1Of2 ( Nil |> async.Return)
501+ | Cons( a, tl) ->
502+ let! b = f a
503+ match b with
504+ | Choice1Of2 b ->
505+ return ! traverseChoiceAsync f tl |> Async.map ( Choice.mapl ( fun tl -> Cons( b, tl) |> async.Return))
506+ | Choice2Of2 e ->
507+ return Choice2Of2 e }
508+
427509 /// Returns elements from an asynchronous sequence while the specified
428510 /// predicate holds. The predicate is evaluated asynchronously.
429511 let rec takeWhileAsync p ( input : AsyncSeq < 'T >) : AsyncSeq < _ > = async {
@@ -492,15 +574,6 @@ module AsyncSeq =
492574 |> fold ( fun arr a -> a:: arr) []
493575 |> Async.map List.rev
494576
495- /// Generates an async sequence using the specified generator function.
496- let rec unfoldAsync ( f : 'State -> Async <( 'T * 'State ) option >) ( s : 'State ) : AsyncSeq < 'T > = asyncSeq {
497- let! r = f s
498- match r with
499- | Some ( a, s) ->
500- yield a
501- yield ! unfoldAsync f s
502- | None -> () }
503-
504577 /// Flattens an AsyncSeq of sequences.
505578 let rec concatSeq ( input : AsyncSeq < #seq < 'T >>) : AsyncSeq < 'T > = asyncSeq {
506579 let! v = input
@@ -529,7 +602,6 @@ module AsyncSeq =
529602
530603 left
531604
532-
533605 /// Buffer items from the async sequence into buffers of a specified size.
534606 /// The last buffer returned may be less than the specified buffer size.
535607 let rec bufferByCount ( bufferSize : int ) ( s : AsyncSeq < 'T >) : AsyncSeq < 'T []> =
@@ -552,7 +624,24 @@ module AsyncSeq =
552624 return ! loop tl
553625 }
554626 return ! loop s
555- }
627+ }
628+
629+ /// Merges two async sequences into an async sequence non-deterministically.
630+ let rec merge ( a : AsyncSeq < 'a >) ( b : AsyncSeq < 'a >) : AsyncSeq < 'a > = async {
631+ let! one , other = Async.chooseBoth a b
632+ match one with
633+ | Nil -> return ! other
634+ | Cons( hd, tl) ->
635+ return Cons( hd, merge tl other) }
636+
637+ /// Merges all specified async sequences into an async sequence non-deterministically.
638+ let rec mergeAll ( ss : AsyncSeq < 'a > list ) : AsyncSeq < 'a > =
639+ match ss with
640+ | [] -> empty
641+ | [ s] -> s
642+ | [ a; b] -> merge a b
643+ | hd:: tl -> merge hd ( mergeAll tl)
644+
556645
557646
558647[<AutoOpen>]
0 commit comments