Skip to content

Documentation says there's a TaskSeq.toAsyncSeq function, but it does not exist #214

Closed

Description

@abelbraaksma

Can we implement this function? To prevent having a dependency on AsyncSeq, we probably need to create this function using SRTP, but it should be possible for users to convert to/from AsyncSeq.

Activity

  1. added
    topic: surface areaAdds functions to the public surface area
    feature requestNew feature or enhancement request
    compatibilityRelated to backward or forwards, or F# Core or .NET version compatibility
    on Dec 19, 2023
  2. added this to the vNext milestone on Mar 18, 2024
  3. njlr commented on Oct 24, 2025

    @njlr
    Contributor

    I needed this internally and came up with this implementation:

    #r "nuget: FSharp.Control.TaskSeq, 0.4.0"
    #r "nuget: FSharp.Control.AsyncSeq, 3.2.1"
    
    open FSharp.Control
    
    [<RequireQualifiedAccess>]
    module TaskSeq =
    
      let toAsyncSeq (xs : TaskSeq<'a>) : AsyncSeq<'a> =
        asyncSeq {
          let! ct = Async.CancellationToken
    
          let en = xs.GetAsyncEnumerator(ct)
    
          try
            while! en.MoveNextAsync().AsTask() |> Async.AwaitTask do
              yield en.Current
          finally
            en.DisposeAsync().AsTask()
            |> Async.AwaitTask
            |> Async.RunSynchronously
        }
    
    let main () =
      let input =
        taskSeq {
          yield "h"
          yield "e"
          yield "l"
          yield "l"
          yield "o"
          yield " "
          yield "w"
          yield "o"
          yield "r"
          yield "l"
          yield "d"
        }
    
      let output =
        input
        |> TaskSeq.toAsyncSeq
    
      async {
        for x in output do
          printfn $"%s{x}"
      }
      |> Async.RunSynchronously
    
    main ()

    Any gotchas I have missed?

    The dispose logic feels nasty.

    Happy to send a PR.

  4. abelbraaksma commented on Nov 14, 2025

    @abelbraaksma
    MemberAuthor

    @njlr thanks, as a quick look, this looks like a fine approach. However, we wouldn't want to have a dependency on AsyncSeq, that would be bad practice. Currently, this lib has zero dependencies and I like it that way.

    The inverse is, as you've mentioned, easier, because the IAsyncEnumerable<'T> type is part of the .NET standard library. But the AsyncSeq library does not use a common interface that I could use.

    I haven't looked at this for a while, I should probably get back into it.

  5. njlr commented on Nov 14, 2025

    @njlr
    Contributor

    Happy to make a PR to https://github.com/fsprojects/FSharp.Control.AsyncSeq for this

    Perhaps names reversed? AsyncSeq.ofTaskSeq

  6. dsyme commented on Mar 7, 2026

    @dsyme
    Contributor

    Latest versions of FSharp.Control.AsyncSeq use

    type AsyncSeq<'T> = System.Collections.Generic.IAsyncEnumerable<'T>
    

    So we have the somewhat strange but highly interoperable situation of

    TaskSeq<'T> = AsyncSeq<'T> = IAsyncEnumerable<'T>
    
  7. dsyme commented on Mar 7, 2026

    @dsyme
    Contributor

    In short, no need to convert anything :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    compatibilityRelated to backward or forwards, or F# Core or .NET version compatibilityfeature requestNew feature or enhancement requesttopic: surface areaAdds functions to the public surface area

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions