This is the the Monad Transformer for seq<'T>
so it adds sequencing to existing monads by composing then with seq<'T>
.
Any monad can be composed, but a very typical usage is when combined with Async
or Task
, which gives rise to what's called async sequences.
Therefore the AsyncSeq library can be considered a specialization of this monad in Async.
The original post from AsyncSeq can be found here and we can run those examples with SeqT
by adapting the code.
In order to do so we need to be aware of the design differences of both implementations.
AsyncSeq<'T>
|
SeqT<Async<bool>, 'T>
|
|
asyncSeq { .. }
|
monad.plus { .. }
|
At some point it needs to be inferred as SeqT<Async<bool>, 'T> , or it can be specified with type parameters: monad<SeqT<Async<bool>, 'T>>.plus |
let! x = y
|
let! x = SeqT.lift y
|
No auto lifting. Lifting should be explicit. |
do! x
|
do! SeqT.lift x
|
'' |
for x in s
|
let! x = s
|
When s: AsyncSeq<'T> otherwise for is still ok with regular sequences. |
AsyncSeq.[function]
|
SeqT.[function]
|
See differences in functions below. |
AsyncSeq.[function]Async
|
SeqT.[function]M
|
'' |
AsyncSeq.skip
|
SeqT.drop
|
.skip is available but consistently with F# collections, it throws when the sequence doesn't have enough elements.
|
AsyncSeq.take
|
SeqT.truncate
|
.take is available but consistently with F# collections, it throws when the sequence doesn't have enough elements.
|
AsyncSeq.toBlockingSequence
|
SeqT.run >> Async.RunSynchronously
|
Not really the same but semantically equivalent. |
AsyncSeq.toListAsync
|
SeqT.runAsList
|
|
AsyncSeq.toArrayAsync
|
SeqT.runAsArray
|
|
AsyncSeq.zipWith
|
SeqT.map2
|
Aligned with F# collections. |
AsyncSeq.zipWithAsync
|
SeqT.map2M
|
'' |
AsyncSeq.ofObservable
|
Observable.toAsyncSeq
|
.toTaskSeq is also available.
|
AsyncSeq.toObservable
|
Observable.ofAsyncSeq
|
.ofTaskSeq is also available.
|
#r "nuget: FSharpPlus"
open System
open System.Net
open FSharpPlus
open FSharpPlus.Data
let urls =
[ "http://bing.com"; "http://yahoo.com";
"http://google.com"; "http://msn.com"; ]
// Asynchronous sequence that returns URLs and lengths
// of the downloaded HTML. Web pages from a given list
// are downloaded asynchronously in sequence.
let pages: SeqT<_, _> = monad.plus {
use wc = new WebClient ()
for url in urls do
try
let! html = wc.AsyncDownloadString (Uri url) |> SeqT.lift
yield url, html.Length
with _ ->
yield url, -1 }
// Print URL of pages that are smaller than 100k
let printPages =
pages
|> SeqT.filter (fun (_, len) -> len < 100000)
|> SeqT.map fst
|> SeqT.iter (printfn "%s")
printPages |> Async.Start
To make it work with tasks simply add |> Async.StartAsTask
between wc.AsyncDownloadString (Uri url)
and |> SeqT.lift
then run eveything but the printPages |> Async.Start
.
namespace System
namespace System.Net
type WebClient =
inherit Component
new: unit -> unit
member CancelAsync: unit -> unit
member DownloadData: address: string -> byte[] + 1 overload
member DownloadDataAsync: address: Uri -> unit + 1 overload
member DownloadDataTaskAsync: address: string -> Task<byte[]> + 1 overload
member DownloadFile: address: string * fileName: string -> unit + 1 overload
member DownloadFileAsync: address: Uri * fileName: string -> unit + 1 overload
member DownloadFileTaskAsync: address: string * fileName: string -> Task + 1 overload
member DownloadString: address: string -> string + 1 overload
...
<summary>Provides common methods for sending data to and receiving data from a resource identified by a URI.</summary>
val wc: System.Net.WebClient
val uri: System.Uri
Multiple items
type Uri =
interface ISerializable
new: uriString: string -> unit + 6 overloads
member Equals: comparand: obj -> bool
member GetComponents: components: UriComponents * format: UriFormat -> string
member GetHashCode: unit -> int
member GetLeftPart: part: UriPartial -> string
member IsBaseOf: uri: Uri -> bool
member IsWellFormedOriginalString: unit -> bool
member MakeRelative: toUri: Uri -> string
member MakeRelativeUri: uri: Uri -> Uri
...
<summary>Provides an object representation of a uniform resource identifier (URI) and easy access to the parts of the URI.</summary>
--------------------
System.Uri(uriString: string) : System.Uri
System.Uri(uriString: string, creationOptions: inref<System.UriCreationOptions>) : System.Uri
System.Uri(uriString: string, uriKind: System.UriKind) : System.Uri
System.Uri(baseUri: System.Uri, relativeUri: string) : System.Uri
System.Uri(baseUri: System.Uri, relativeUri: System.Uri) : System.Uri
val async: AsyncBuilder
<summary>Builds an asynchronous workflow using computation expression syntax.</summary>
<example id="async-1"><code lang="fsharp">
let sleepExample() =
async {
printfn "sleeping"
do! Async.Sleep 10
printfn "waking up"
return 6
}
sleepExample() |> Async.RunSynchronously
</code></example>
System.Net.WebClient.DownloadString(address: System.Uri) : string
System.Net.WebClient.DownloadString(address: string) : string
namespace FSharpPlus
namespace FSharpPlus.Data
val urls: string list
val pages: SeqT<Async<bool>,(string * int)>
Multiple items
static member SeqTOperations.SeqT: source: 'Monad<seq<'T>> -> SeqT<'Monad<bool>,'T> (requires member (>>=) and member Return)
--------------------
active recognizer SeqT: SeqT<'Monad<bool>,'T> -> 'Monad<'T seq>
--------------------
module SeqT
from FSharpPlus.Data.SeqT_V2
--------------------
[<Struct>]
type SeqT<'monad,'t> =
| SeqT of IEnumerableM<'monad,'t>
interface IEnumerableM<'monad,'t>
static member ( *> ) : x: SeqT<'Monad<bool>,'T> * y: SeqT<'Monad<bool>,'U> -> SeqT<'Monad<bool>,'U> (requires member (>>=) and member Return and member Delay)
static member (<!>) : x: SeqT<'Monad<bool>,'T> * f: ('T -> 'U) -> SeqT<'Monad<bool>,'U> (requires member Delay and member (>>=) and member Return)
static member ( <* ) : x: SeqT<'Monad<bool>,'U> * y: SeqT<'Monad<bool>,'T> -> SeqT<'Monad<bool>,'U> (requires member (>>=) and member Return and member Delay)
static member (<*>) : f: SeqT<'Monad<bool>,('T -> 'U)> * x: SeqT<'Monad<bool>,'T> -> SeqT<'Monad<bool>,'U> (requires member (>>=) and member Return)
static member (<|>) : x: SeqT<'Monad<bool>,'T> * y: SeqT<'Monad<bool>,'T> -> SeqT<'Monad<bool>,'T> (requires member Delay and member Return and member (>>=))
static member (>>=) : x: SeqT<'Monad<bool>,'T> * f: ('T -> SeqT<'Monad<bool>,'U>) -> SeqT<'Monad<bool>,'U> (requires member (>>=) and member Return)
static member CallCC: f: (('T -> SeqT<'MonadCont<'R>,'U>) -> SeqT<'a5,'a7>) -> SeqT<'MonadCont<'R>,'T> (requires member (>>=) and member Return and member (>>=) and member (>>=) and member Using and member (>>=) and member Return and member CallCC and member (>>=) and member (>>=) and member Return)
static member Catch: m: SeqT<'MonadError<'E1>,'T> * h: ('E1 -> SeqT<'MonadError<'E2>,'T>) -> SeqT<'MonadError<'E2>,'T> (requires member (>>=) and member (>>=) and member Using and member (>>=) and member Return and member Catch and member (>>=) and member Return and member (>>=) and member Using and member (>>=) and member Return and member (>>=) and member Return and member (>>=) and member (>>=) and member Return)
static member Delay: body: (unit -> SeqT<'Monad<bool>,'T>) -> SeqT<'Monad<bool>,'T>
...
val monad<'monad<'t>> : MonadFxBuilder<'monad<'t>>
<summary>
Creates a (lazy) monadic computation expression with side-effects (see http://fsprojects.github.io/FSharpPlus/computation-expressions.html for more information)
</summary>
val wc: WebClient
val url: string
val html: string
member WebClient.AsyncDownloadString: address: Uri -> Async<string>
member WebClient.AsyncDownloadString: uri: Uri -> Async<string>
<summary>Returns an asynchronous computation that, when run, will wait for the download of the given URI.</summary>
<param name="address">The URI to retrieve.</param>
<returns>An asynchronous computation that will wait for the download of the URI.</returns>
<example id="async-download-string"><code lang="fsharp">
open System
let client = new WebClient()
Uri("https://www.w3.org") |> client.AsyncDownloadString |> Async.RunSynchronously
</code>
This will download the server response from https://www.w3.org
</example>
Multiple items
type Uri =
interface ISerializable
new: uriString: string -> unit + 6 overloads
member Equals: comparand: obj -> bool
member GetComponents: components: UriComponents * format: UriFormat -> string
member GetHashCode: unit -> int
member GetLeftPart: part: UriPartial -> string
member IsBaseOf: uri: Uri -> bool
member IsWellFormedOriginalString: unit -> bool
member MakeRelative: toUri: Uri -> string
member MakeRelativeUri: uri: Uri -> Uri
...
<summary>Provides an object representation of a uniform resource identifier (URI) and easy access to the parts of the URI.</summary>
--------------------
Uri(uriString: string) : Uri
Uri(uriString: string, creationOptions: inref<UriCreationOptions>) : Uri
Uri(uriString: string, uriKind: UriKind) : Uri
Uri(baseUri: Uri, relativeUri: string) : Uri
Uri(baseUri: Uri, relativeUri: Uri) : Uri
Multiple items
val lift: source: 'Monad<'T> -> SeqT<'Monad<bool>,'T> (requires member (>>=) and member Map and member Return)
--------------------
val lift: x: 'Monad<'T> -> SeqT<'Monad<seq<'T>>> (requires member (>>=) and member Map and member Return)
<summary>
Embed a Monad<'T> into a SeqT<'Monad<seq<'T>>>
</summary>
property String.Length: int with get
val printPages: Async<unit>
val filter: f: ('T -> bool) -> source: SeqT<'Monad<bool>,'T> -> SeqT<'Monad<bool>,'T> (requires member Delay and member (>>=) and member Return)
val len: int
Multiple items
val map: f: ('T -> 'U) -> source: SeqT<'Monad<bool>,'T> -> SeqT<'Monad<bool>,'U> (requires member Delay and member (>>=) and member Return)
--------------------
val map: f: ('T -> 'U) -> SeqT<'Monad<seq<'T>> -> SeqT<'Monad<seq<'U>> (requires member Map)
val fst: tuple: ('T1 * 'T2) -> 'T1
<summary>Return the first element of a tuple, <c>fst (a,b) = a</c>.</summary>
<param name="tuple">The input tuple.</param>
<returns>The first value.</returns>
<example id="fst-example"><code lang="fsharp">
fst ("first", 2) // Evaluates to "first"
</code></example>
val iter: f: ('T -> unit) -> source: SeqT<'Monad<bool>,'T> -> 'Monad<unit> (requires member (>>=) and member Delay and member Using and member Return and member (>>=))
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
<summary>Print to <c>stdout</c> using the given format, and add a newline.</summary>
<param name="format">The formatter.</param>
<returns>The formatted result.</returns>
<example>See <c>Printf.printfn</c> (link: <see cref="M:Microsoft.FSharp.Core.PrintfModule.PrintFormatLine``1" />) for examples.</example>
Multiple items
module Async
from FSharpPlus
<summary>
Additional operations on Async
</summary>
--------------------
type Async =
static member AsBeginEnd: computation: ('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -> Async<bool>
static member AwaitTask: task: Task<'T> -> Async<'T> + 1 overload
static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -> Async<bool>
static member CancelDefaultToken: unit -> unit
static member Catch: computation: Async<'T> -> Async<Choice<'T,exn>>
static member Choice: computations: seq<Async<'T option>> -> Async<'T option>
static member FromBeginEnd: beginAction: (AsyncCallback * obj -> IAsyncResult) * endAction: (IAsyncResult -> 'T) * ?cancelAction: (unit -> unit) -> Async<'T> + 3 overloads
static member FromContinuations: callback: (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
...
<summary>Holds static members for creating and manipulating asynchronous computations.</summary>
<remarks>
See also <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/asynchronous-workflows">F# Language Guide - Async Workflows</a>.
</remarks>
<category index="1">Async Programming</category>
--------------------
type Async<'T>
<summary>
An asynchronous computation, which, when run, will eventually produce a value of type T, or else raises an exception.
</summary>
<remarks>
This type has no members. Asynchronous computations are normally specified either by using an async expression
or the static methods in the <see cref="T:Microsoft.FSharp.Control.FSharpAsync`1" /> type.
See also <a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/asynchronous-workflows">F# Language Guide - Async Workflows</a>.
</remarks>
<namespacedoc><summary>
Library functionality for asynchronous programming, events and agents. See also
<a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/asynchronous-workflows">Asynchronous Programming</a>,
<a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/members/events">Events</a> and
<a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/lazy-expressions">Lazy Expressions</a> in the
F# Language Guide.
</summary></namespacedoc>
<category index="1">Async Programming</category>
static member Async.Start: computation: Async<unit> * ?cancellationToken: Threading.CancellationToken -> unit