Search code examples
f#computation-expression

can't compile code in computation expression, in F#


I have this function:

let rec retryAsync<'a> (shouldRetry: 'a -> bool) (retryIntervals: TimeSpan list) (onRetryNotice: int -> unit) (request: unit -> Async<'a>) : Async<'a> =
    async {
        let! result = request()
        match shouldRetry result, retryIntervals with
        | true, head::rest ->
            onRetryNotice retryIntervals.Length
            Thread.Sleep(head)
            return! retryAsync shouldRetry rest onRetryNotice request
        | false, _
        | _, [] ->
            return result
    }

I use it in an asyncResult block like this:

asyncResult {
    let! x = Retry.retryAsync
                 Retry.shouldRetryExchange
                 Retry.defaultRetryIntervals
                 (fun r -> warn $"retry {r}/{Retry.defaultRetryIntervals.Length}")
                 (fun _ -> loadExchangeSettingsAsync rest)
    ...
    return ...
}

but in some cases, I want to ignore the result; however:

asyncResult {
    do!  Retry.retryAsync
             Retry.shouldRetryExchange
             Retry.defaultRetryIntervals
             (fun r -> warn $"retry {r}/{Retry.defaultRetryIntervals.Length}")
             (fun _ -> loadExchangeSettingsAsync rest)
    ...
    return ...
}

will give me:

[FS0001] This expression was expected to have type 'Result<unit,ExchangeError>' but here has type 'unit'

I don't understand why since the expression is returning the right type, it's the same one as above.


Solution

  • do! only works on expressions that return Async<unit>, so you'll have to pipe it to Async.Ignore first:

    do!  Retry.retryAsync
                 Retry.shouldRetryExchange
                 Retry.defaultRetryIntervals
                 (fun r -> warn $"retry {r}/{Retry.defaultRetryIntervals.Length}")
                 (fun _ -> loadExchangeSettingsAsync rest)
         |> Async.Ignore