Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement For on the built-in TaskBuilder #75

Closed
Tarmil opened this issue Nov 5, 2022 · 4 comments · Fixed by #93
Closed

Implement For on the built-in TaskBuilder #75

Tarmil opened this issue Nov 5, 2022 · 4 comments · Fixed by #93
Assignees
Labels
feature request New feature or enhancement request topic: ce extensions Extensions to other CE's like task or async
Milestone

Comments

@Tarmil
Copy link

Tarmil commented Nov 5, 2022

It would be useful to add an extension method For on TaskBuilder to be able to do for loops over IAsyncEnumerable in tasks.

let mySeq =
    taskSeq {
        for i in 0..9 do yield i
    }

let myTask =
    task {
        for x in mySeq do // <-- This is currently not possible.
            printfn $"{x}"
    }
@abelbraaksma
Copy link
Member

abelbraaksma commented Nov 5, 2022

Thanks for this suggestion! You mean on task, not taskSeq, right? I wonder if I can create an extension method using resumable state, haven't tried that yet. I'll have to think about this a little, as the items in the for-loop need to be awaited.

I certainly see the usefulness of this addition.

For the time being, you can do this, which may not be ideal. The toSeq is currently only available in a cached version, hence the toListAsync here. Obviously this materializes the whole sequence, which is probably not what you'd want in async sequences:

let mySeq =
    taskSeq {
        for i in 0..9 do yield i
    }
let x = task {
    let! l = mySeq |> TaskSeq.toListAsync
    for x in l do
        let y = x + 1
        printfn $"{y}"
}

Do note that this can only ever work for executing side effects: the for loop must return unit.

@dsyme
Copy link
Contributor

dsyme commented Nov 5, 2022

Here's the equivalent in the AsyncSeq library: https://github.com/fsprojects/FSharp.Control.AsyncSeq/blob/1023d8a203acb7dd3f395bf25223bbe8a79d9e80/src/FSharp.Control.AsyncSeq/AsyncSeq.fs#L1819

So yes we should an equivalent add to TaskBuilder

@abelbraaksma abelbraaksma added the feature request New feature or enhancement request label Nov 6, 2022
@abelbraaksma
Copy link
Member

abelbraaksma commented Nov 14, 2022

This turns out to be a bit trickier than I thought. This has to do with the MoveNextAsync and the task builder expecting a TaskCode. I.e., I cannot add extensions that return Task<'T> (if I do, they aren't recognized).

First I figured I could use ResumableCode.For, but that expects a non-async seq. So, I figured I could do it with ResumableCode.While or task.While, but the condition in While cannot be asynchronous, i.e., the condition here fails to compile:

member inline this.For(tasksq: IAsyncEnumerable<'T>, body: 'T -> TaskCode<'TOverall, unit>) : TaskCode<'TOverall, unit> =
    TaskCode<'TOverall, unit>(fun sm ->
        this
            .Using(
                tasksq.GetAsyncEnumerator(CancellationToken()),
                (fun e -> this.While((fun () -> e.MoveNextAsync()), (fun sm -> (body e.Current).Invoke(&sm))))
            )
            .Invoke(&sm))

It's probably not so hard in the end, just need to give it another look.

PS, for async a similar extension is trivial:

member x.For(tasksq: IAsyncEnumerable<'T>, action: 'T -> Async<unit>) =
    tasksq
    |> TaskSeq.iterAsync (action >> Async.StartAsTask)
    |> Async.AwaitTask

@abelbraaksma
Copy link
Member

abelbraaksma commented Nov 26, 2022

@Tarmil thanks for making this request. The changes have been made in #93 (and #99, with help from @TheAngryByrd) and are merged. They'll be part of the upcoming v0.3.0, which I'll publish later today.

The solution uses resumable code for task and normal code for async.

@abelbraaksma abelbraaksma added this to the v0.3.0 milestone Mar 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or enhancement request topic: ce extensions Extensions to other CE's like task or async
Projects
None yet
3 participants