fsprojects / FSharp.Control.TaskSeq

A computation expression and module for seamless working with IAsyncEnumerable<'T> as if it is just another sequence
MIT License
91 stars 7 forks source link

Consider tail recursion #62

Open abelbraaksma opened 1 year ago

abelbraaksma commented 1 year ago

We've removed the tail recursion because it was hard to consolidate it into yield! (it was instead done with return!, which has no place in taskSeq).

However, today I helped someone with some code that he considered for taskSeq which had the following approach:

let getPoliciesAsync policyid =
    asyncSeq{
        use connection = new NpgsqlConnection(npgsqlConnectionStringBuilder.ConnectionString)
        use command = new NpgsqlCommand($"SELECT policy_data FROM policy.tbl_policy where policy_id = {Sql.uuid policyid};", connection)
        let! reader = command.ExecuteReaderAsync() |> Async.AwaitTask
        let rec someRec() = asyncSeq{
            let! rowExists = reader.ReadAsync() |> Async.AwaitTask
            if rowExists then
                yield {| dt1 = reader.GetString(0) |}
                yield! someRec()
        }
        yield! someRec()
    } |> AsyncSeq.toAsyncEnum

As you can see, it uses asyncSeq, but also: it is recursive. The same approach with taskSeq would likely be more performant, however, if there are a lot of rows, this becomes problematic. This code can be rewritten with a loop, though.

@dsyme, sharing this with you in case we want to revisit this at some point.

dsyme commented 1 year ago

Yes, this should be rewritten with a loop

dsyme commented 1 year ago

@abelbraaksma BTW I think I am going to prioritise an F# 8 addition to allow builders to specify ReturnFromTailcall or YieldFromTailcall methods.

abelbraaksma commented 1 year ago

@dsyme that would certainly simplify an addition like this, and would also allow task to support tail calls. Awesome! We can do some early-adoption testing here through TaskSeq.

abelbraaksma commented 10 months ago

See https://github.com/fsharp/fslang-suggestions/issues/1006 instead.