I'm playing around with using SqlClient in F# and I'm having difficulty with using SqlDataReader.ReadAsync. I'm trying to do the F# equivalent of
while (await reader.ReadAsync) { ... }
What is the best way to do this in F#? Below is my full program. It works, but I'd like to know if there is a better way to do it.
open System
open System.Data.SqlClient
open System.Threading.Tasks
let connectionString = "Server=.;Integrated Security=SSPI"
module Async =
    let AwaitVoidTask : (Task -> Async<unit>) =
        Async.AwaitIAsyncResult >> Async.Ignore
    // QUESTION: Is this idiomatic F#? Is there a more generally-used way of doing this?
    let rec While (predicateFn : unit -> Async<bool>) (action : unit -> unit) : Async<unit> = 
        async {
            let! b = predicateFn()
            match b with
                | true -> action(); do! While predicateFn action
                | false -> ()
        }
[<EntryPoint>]
let main argv = 
    let work = async {
        // Open connection
        use conn = new SqlConnection(connectionString)
        do! conn.OpenAsync() |> Async.AwaitVoidTask
        // Execute command
        use cmd = conn.CreateCommand()
        cmd.CommandText <- "select name from sys.databases"
        let! reader = cmd.ExecuteReaderAsync() |> Async.AwaitTask
        // Consume reader
        // I want a convenient 'while' loop like this...
        //while reader.ReadAsync() |> Async.AwaitTask do // Error: This expression was expected to have type bool but here has type Async<bool>
        //    reader.GetValue 0 |> string |> printfn "%s"
        // Instead I used the 'Async.While' method that I defined above.
        let ConsumeReader = Async.While (fun () -> reader.ReadAsync() |> Async.AwaitTask)
        do! ConsumeReader (fun () -> reader.GetValue 0 |> string |> printfn "%s")
    }
    work |> Async.RunSynchronously
    0 // return an integer exit code
 
     
    